1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
use std::{
    cmp::min,
    convert::TryInto,
    ptr::{null, null_mut},
};
use widestring::U16CStr;
/// Clamps a usize between `0` and `i16::MAX`.
pub fn clamp_small_int(n: usize) -> i16 {
    min(n, i16::MAX as usize) as i16
}
/// Clamps a usize between `0` and `i32::MAX`.
pub fn clamp_int(n: usize) -> i32 {
    min(n, i32::MAX as usize) as i32
}
/// Returns a pointer suitable to be passed as an output buffer to ODBC functions. Most notably it
/// will return NULL for empty buffers.
pub fn mut_buf_ptr<T>(buffer: &mut [T]) -> *mut T {
    if buffer.is_empty() {
        null_mut()
    } else {
        buffer.as_mut_ptr()
    }
}
/// Returns a pointer suitable to be passed as an output buffer to ODBC functions. Most notably it
/// will return NULL for empty buffers.
pub fn buf_ptr<T>(buffer: &[T]) -> *const T {
    if buffer.is_empty() {
        null()
    } else {
        buffer.as_ptr()
    }
}
/// We use this as an output buffer for strings. Allows for detecting truncation.
pub struct OutputStringBuffer {
    /// Buffer holding the string. This crate uses wide methods (i.e. UTF-16) so we allocate a
    /// `Vec<u16>` instead of a `Vec<u8>`. Must also contain space for a terminating zero.
    buffer: Vec<u16>,
    /// After the buffer has been filled, this should contain the actual length of the string. Can
    /// be used to detect truncation.
    actual_length: i16,
}
impl OutputStringBuffer {
    /// Creates a new instance of an output string buffer which can hold strings up to a size of
    /// `max_str_len` characters.
    pub fn with_buffer_size(max_str_len: usize) -> Self {
        Self {
            buffer: vec![0; max_str_len + 1],
            actual_length: 0,
        }
    }
    /// Ptr to the internal buffer. Used by ODBC API calls to fill the buffer.
    pub fn mut_buf_ptr(&mut self) -> *mut u16 {
        mut_buf_ptr(&mut self.buffer)
    }
    /// Length of the internal buffer in characters excluding the terminating zero.
    pub fn buf_len(&self) -> i16 {
        if self.buffer.is_empty() {
            0
        } else {
            (self.buffer.len() - 1).try_into().unwrap()
        }
    }
    /// Mutable pointer to actual output string length. Used by ODBC API calls to report truncation.
    pub fn mut_actual_len_ptr(&mut self) -> *mut i16 {
        &mut self.actual_length as *mut i16
    }
    /// Interpret buffer as UTF16 string. Panics if no terminating zero present.
    pub fn as_ucstr(&self) -> &U16CStr {
        U16CStr::from_slice_with_nul(&self.buffer).unwrap()
    }
    /// Call this method to extract string from buffer after ODBC has filled it.
    pub fn to_utf8(&self) -> String {
        self.as_ucstr().to_string().unwrap()
    }
    /// True if the buffer had not been large enough to hold the string.
    pub fn is_truncated(&self) -> bool {
        let len: usize = self.actual_length.try_into().unwrap();
        // One character is needed for the terminating zero, but string size is reported in
        // characters without terminating zero.
        len >= self.buffer.len()
    }
}