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_truncate(&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()
}
}