odbc_api/handles/
sql_char.rs1use super::buffer::{buf_ptr, mut_buf_ptr};
17use std::{
18 borrow::Cow,
19 mem::{size_of, size_of_val},
20};
21
22#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
23use std::{ffi::CStr, string::FromUtf8Error};
24
25#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
26use std::{
27 char::{DecodeUtf16Error, decode_utf16},
28 marker::PhantomData,
29};
30
31#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
32use widestring::{U16CStr, Utf16String, iter::EncodeUtf16};
33
34#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
35pub type SqlChar = u8;
36#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
37pub type SqlChar = u16;
38
39#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
40pub type DecodingError = FromUtf8Error;
41#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
42pub type DecodingError = DecodeUtf16Error;
43
44#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
45pub fn slice_to_utf8(text: &[u8]) -> Result<String, FromUtf8Error> {
46 String::from_utf8(text.to_owned())
47}
48#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
49pub fn slice_to_utf8(text: &[u16]) -> Result<String, DecodeUtf16Error> {
50 decode_utf16(text.iter().copied()).collect()
51}
52
53#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
54pub fn slice_to_cow_utf8(text: &[u8]) -> Cow<'_, str> {
55 String::from_utf8_lossy(text)
56}
57#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
58pub fn slice_to_cow_utf8(text: &[u16]) -> Cow<'_, str> {
59 let text: Result<String, _> = decode_utf16(text.iter().copied()).collect();
60 text.unwrap().into()
61}
62
63#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
64fn sz_to_utf8(buffer: &[u16]) -> String {
65 let c_str = U16CStr::from_slice_truncate(buffer).unwrap();
66 c_str.to_string_lossy()
67}
68
69#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
70fn sz_to_utf8(buffer: &[u8]) -> String {
71 let end = buffer
73 .iter()
74 .enumerate()
75 .find(|&(_index, &character)| character == b'\0')
76 .expect("Buffer must contain terminating zero.")
77 .0;
78 let c_str = unsafe { CStr::from_bytes_with_nul_unchecked(&buffer[..=end]) };
79 c_str.to_string_lossy().into_owned()
80}
81
82#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
83pub const WHITESPACE: SqlChar = 0x0020;
84
85#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
86pub const WHITESPACE: SqlChar = 0x20;
87
88pub fn binary_length(buffer: &[SqlChar]) -> usize {
90 size_of_val(buffer)
91}
92
93pub fn is_truncated_bin(buffer: &[SqlChar], actual_length_bin: usize) -> bool {
99 size_of_val(buffer) <= actual_length_bin
100}
101
102pub fn resize_to_fit_with_tz(buffer: &mut Vec<SqlChar>, required_binary_length: usize) {
106 buffer.resize((required_binary_length / size_of::<SqlChar>()) + 2, 0);
111}
112
113pub fn resize_to_fit_without_tz(buffer: &mut Vec<SqlChar>, required_binary_length: usize) {
117 buffer.resize(required_binary_length / size_of::<SqlChar>(), 0);
118}
119
120pub struct SqlText<'a> {
125 #[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
128 text: Utf16String,
129 #[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
132 _ref: PhantomData<&'a str>,
133 #[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
135 text: &'a str,
136}
137
138impl<'a> SqlText<'a> {
139 #[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
140 pub fn new(text: &'a str) -> Self {
142 Self {
143 text: Utf16String::from_str(text),
144 _ref: PhantomData,
145 }
146 }
147 #[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
148 pub fn new(text: &'a str) -> Self {
150 Self { text }
151 }
152
153 #[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
154 pub fn ptr(&self) -> *const u16 {
155 buf_ptr(self.text.as_slice())
156 }
157 #[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
158 pub fn ptr(&self) -> *const u8 {
159 buf_ptr(self.text.as_bytes())
160 }
161
162 pub fn len_char(&self) -> usize {
164 self.text.len()
165 }
166}
167
168pub struct SzBuffer {
171 buffer: Vec<SqlChar>,
172}
173
174impl SzBuffer {
175 pub fn with_capacity(capacity: usize) -> Self {
179 Self {
180 buffer: vec![0; capacity + 1],
182 }
183 }
184
185 pub fn mut_buf(&mut self) -> &mut [SqlChar] {
186 self.buffer.resize(self.buffer.capacity(), 0);
188 &mut self.buffer
189 }
190
191 pub fn to_utf8(&self) -> String {
193 sz_to_utf8(&self.buffer)
194 }
195}
196
197pub struct OutputStringBuffer {
199 buffer: Vec<SqlChar>,
201 actual_length: i16,
204}
205
206impl OutputStringBuffer {
207 pub fn empty() -> Self {
210 Self::with_buffer_size(0)
211 }
212
213 pub fn with_buffer_size(max_str_len: usize) -> Self {
217 Self {
218 buffer: vec![0; max_str_len],
219 actual_length: 0,
220 }
221 }
222
223 pub fn mut_buf_ptr(&mut self) -> *mut SqlChar {
225 mut_buf_ptr(&mut self.buffer)
226 }
227
228 pub fn buf_len(&self) -> i16 {
230 self.buffer.len().try_into().unwrap()
233 }
234
235 pub fn mut_actual_len_ptr(&mut self) -> *mut i16 {
237 &mut self.actual_length as *mut i16
238 }
239
240 pub fn to_utf8(&self) -> String {
242 if self.buffer.is_empty() {
243 return String::new();
244 }
245
246 if self.is_truncated() {
247 slice_to_utf8(&self.buffer[0..(self.buffer.len() - 1)]).unwrap()
250 } else {
251 let actual_length: usize = self.actual_length.try_into().unwrap();
254 slice_to_utf8(&self.buffer[0..actual_length]).unwrap()
255 }
256 }
257
258 pub fn is_truncated(&self) -> bool {
260 self.actual_length >= self.buffer.len().try_into().unwrap()
261 }
262}