rs_odbc/
convert.rs

1use crate::{
2    c_types::CScalar,
3    conn::ConnState,
4    desc::DescType,
5    env::OdbcVersion,
6    handle::{
7        RefSQLHDESC, RefUnsafeSQLHDESC, UnsafeSQLHDESC, UnsafeSQLHSTMT, SQLHANDLE, SQLHDBC,
8        SQLHDESC, SQLHENV, SQLHSTMT, SQL_NULL_HANDLE,
9    },
10    slice_len,
11    str::{Ansi, OdbcChar, OdbcStr, Unicode},
12    Scalar, SQLCHAR, SQLINTEGER, SQLLEN, SQLPOINTER, SQLSMALLINT, SQLUINTEGER, SQLULEN,
13    SQLUSMALLINT, SQLWCHAR,
14};
15use core::{cell::UnsafeCell, fmt::Debug, mem::MaybeUninit};
16
17/// Used to do a cheap mutable reference-to-raw pointer conversion.
18///
19/// # Invariant
20///
21/// Implementing types must support all possible values for T because
22/// any valid T value can be written to the obtained raw mut pointer
23pub unsafe trait AsMutPtr<T> {
24    fn as_mut_ptr(&mut self) -> *mut T;
25}
26
27/// A value-to-SQLPOINTER conversion that consumes the input value.
28/// Invariant: SQLPOINTER obtained through this trait is never written to
29pub unsafe trait IntoSQLPOINTER: Copy {
30    #[allow(non_snake_case)]
31    fn into_SQLPOINTER(self) -> SQLPOINTER;
32}
33
34/// Used to do a cheap reference-to-SQLPOINTER conversion.
35/// Invariant: SQLPOINTER obtained through this trait is never written to
36pub unsafe trait AsSQLPOINTER {
37    #[allow(non_snake_case)]
38    fn as_SQLPOINTER(&self) -> SQLPOINTER;
39}
40
41/// Used to do a cheap mutable reference-to-SQLPOINTER conversion.
42pub unsafe trait AsMutSQLPOINTER {
43    #[allow(non_snake_case)]
44    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER;
45}
46
47/// Used to do a cheap slice-to-raw slice conversion.
48/// Invariant: raw pointer obtained through this trait is never written to
49pub(crate) unsafe trait AsRawSlice<CH, LEN: Copy> {
50    fn as_raw_slice(&self) -> (*const CH, LEN);
51}
52
53/// Used to do a cheap mutable slice-to-raw slice conversion.
54pub(crate) unsafe trait AsMutRawSlice<CH, LEN: Copy> {
55    fn as_mut_raw_slice(&mut self) -> (*mut CH, LEN);
56}
57
58pub unsafe trait AsSQLHANDLE {
59    #[allow(non_snake_case)]
60    fn as_SQLHANDLE(&self) -> SQLHANDLE;
61}
62
63////////////////////////////////////////////////////////////////////////////////
64// GENERIC IMPLS
65////////////////////////////////////////////////////////////////////////////////
66
67unsafe impl<T: Scalar> AsMutPtr<T> for T {
68    fn as_mut_ptr(&mut self) -> *mut T {
69        self
70    }
71}
72unsafe impl<T: AsMutPtr<T>> AsMutPtr<T> for MaybeUninit<T> {
73    fn as_mut_ptr(&mut self) -> *mut T {
74        self.as_mut_ptr()
75    }
76}
77unsafe impl<T: Scalar> IntoSQLPOINTER for &T {
78    fn into_SQLPOINTER(self) -> SQLPOINTER {
79        self as *const _ as SQLPOINTER
80    }
81}
82unsafe impl<T> IntoSQLPOINTER for &[T] {
83    fn into_SQLPOINTER(self) -> SQLPOINTER {
84        // Casting from const to mutable raw pointer is safe because of the invariant
85        // that SQLPOINTER obtained through IntoSQLPOINTER will never be written to
86        (self.as_ptr() as *mut T).cast()
87    }
88}
89unsafe impl<CH: OdbcChar> IntoSQLPOINTER for &OdbcStr<CH> {
90    fn into_SQLPOINTER(self) -> SQLPOINTER {
91        // Casting from const to mutable raw pointer is safe because of the invariant
92        // that SQLPOINTER obtained through IntoSQLPOINTER will never be written to
93        (self.as_ptr() as *mut CH).cast()
94    }
95}
96unsafe impl<T: CScalar> IntoSQLPOINTER for &UnsafeCell<T> {
97    fn into_SQLPOINTER(self) -> SQLPOINTER {
98        self.get().cast()
99    }
100}
101unsafe impl<T: CScalar> AsSQLPOINTER for T {
102    fn as_SQLPOINTER(&self) -> SQLPOINTER {
103        // CScalar is guaranteed to have SQLPOINTER representation
104        self as *const _ as SQLPOINTER
105    }
106}
107unsafe impl<T: CScalar> AsSQLPOINTER for UnsafeCell<T> {
108    fn as_SQLPOINTER(&self) -> SQLPOINTER {
109        // CScalar is guaranteed to have SQLPOINTER representation
110        self.get().cast()
111    }
112}
113unsafe impl<T> AsSQLPOINTER for [T] {
114    fn as_SQLPOINTER(&self) -> SQLPOINTER {
115        // Casting from const to mutable raw pointer is ok because of the invariant
116        // that SQLPOINTER obtained through AsSQLPOINTER will never be written to
117        (self.as_ptr() as *mut T).cast()
118    }
119}
120unsafe impl<T> AsSQLPOINTER for OdbcStr<T> {
121    fn as_SQLPOINTER(&self) -> SQLPOINTER {
122        // Casting from const to mutable raw pointer is ok because of the invariant
123        // that SQLPOINTER obtained through AsSQLPOINTER will never be written to
124        (self.as_ptr() as *mut T).cast()
125    }
126}
127
128unsafe impl<T: CScalar> AsMutSQLPOINTER for T {
129    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
130        // CScalar is guaranteed to have SQLPOINTER representation
131        (self as *mut Self).cast()
132    }
133}
134unsafe impl<T: CScalar> AsMutSQLPOINTER for MaybeUninit<T> {
135    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
136        // CScalar is guaranteed to have SQLPOINTER representation
137        self.as_mut_ptr().cast()
138    }
139}
140unsafe impl<T> AsMutSQLPOINTER for [T] {
141    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
142        self.as_mut_ptr().cast()
143    }
144}
145unsafe impl<T> AsMutSQLPOINTER for OdbcStr<T> {
146    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
147        <[T] as AsMutSQLPOINTER>::as_mut_SQLPOINTER(self)
148    }
149}
150unsafe impl<T: AsMutSQLPOINTER> AsMutSQLPOINTER for UnsafeCell<T> {
151    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
152        self.get_mut().as_mut_SQLPOINTER()
153    }
154}
155
156unsafe impl<CH, LEN: TryFrom<usize>> AsRawSlice<CH, LEN> for OdbcStr<CH>
157where
158    LEN: Copy,
159    LEN::Error: Debug,
160{
161    fn as_raw_slice(&self) -> (*const CH, LEN) {
162        (self.as_ptr(), slice_len(self))
163    }
164}
165
166unsafe impl<CH, LEN: TryFrom<usize>> AsMutRawSlice<SQLCHAR, LEN> for OdbcStr<CH>
167where
168    LEN: Copy,
169    LEN::Error: Debug,
170    Self: Ansi,
171{
172    fn as_mut_raw_slice(&mut self) -> (*mut SQLCHAR, LEN) {
173        (self.as_mut_ptr().cast(), slice_len(self))
174    }
175}
176unsafe impl<CH, LEN: TryFrom<usize>> AsMutRawSlice<SQLWCHAR, LEN> for OdbcStr<CH>
177where
178    LEN: Copy,
179    LEN::Error: Debug,
180    Self: Unicode,
181{
182    fn as_mut_raw_slice(&mut self) -> (*mut SQLWCHAR, LEN) {
183        (self.as_mut_ptr().cast(), slice_len(self))
184    }
185}
186
187////////////////////////////////////////////////////////////////////////////////
188// CONCRETE IMPLS
189////////////////////////////////////////////////////////////////////////////////
190
191unsafe impl IntoSQLPOINTER for SQLSMALLINT {
192    fn into_SQLPOINTER(self) -> SQLPOINTER {
193        self as SQLPOINTER
194    }
195}
196unsafe impl IntoSQLPOINTER for SQLUSMALLINT {
197    fn into_SQLPOINTER(self) -> SQLPOINTER {
198        self as SQLPOINTER
199    }
200}
201unsafe impl IntoSQLPOINTER for SQLINTEGER {
202    fn into_SQLPOINTER(self) -> SQLPOINTER {
203        self as SQLPOINTER
204    }
205}
206unsafe impl IntoSQLPOINTER for SQLUINTEGER {
207    fn into_SQLPOINTER(self) -> SQLPOINTER {
208        self as SQLPOINTER
209    }
210}
211unsafe impl IntoSQLPOINTER for SQLLEN {
212    fn into_SQLPOINTER(self) -> SQLPOINTER {
213        self as SQLPOINTER
214    }
215}
216unsafe impl IntoSQLPOINTER for SQLULEN {
217    fn into_SQLPOINTER(self) -> SQLPOINTER {
218        self as SQLPOINTER
219    }
220}
221unsafe impl<'buf, V: OdbcVersion, T: DescType<'buf>> IntoSQLPOINTER
222    for Option<&SQLHDESC<'_, T, V>>
223{
224    fn into_SQLPOINTER(self) -> SQLPOINTER {
225        self.map_or_else(core::ptr::null_mut, |handle| {
226            Some(&handle.0).into_SQLPOINTER()
227        })
228    }
229}
230unsafe impl<'buf, V: OdbcVersion, T: DescType<'buf>> IntoSQLPOINTER
231    for Option<&UnsafeSQLHDESC<'_, T, V>>
232{
233    fn into_SQLPOINTER(self) -> SQLPOINTER {
234        self.map_or_else(core::ptr::null_mut, |handle| handle.as_SQLHANDLE().cast())
235    }
236}
237
238unsafe impl AsSQLPOINTER for (SQLPOINTER, SQLLEN) {
239    fn as_SQLPOINTER(&self) -> SQLPOINTER {
240        self.0
241    }
242}
243
244unsafe impl AsMutSQLPOINTER for SQLLEN {
245    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
246        (self as *mut Self).cast()
247    }
248}
249unsafe impl AsMutSQLPOINTER for SQLULEN {
250    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
251        (self as *mut Self).cast()
252    }
253}
254unsafe impl<DT, V: OdbcVersion> AsMutSQLPOINTER for MaybeUninit<RefUnsafeSQLHDESC<'_, DT, V>> {
255    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
256        if cfg!(feature = "odbc_debug") {
257            // SQLHDESC is not transparent
258            unimplemented!("This method should never be called")
259        }
260
261        // SQLHDESC is transparent
262        self.as_mut_ptr().cast()
263    }
264}
265unsafe impl<'conn, 'desc, DT, V: OdbcVersion> AsMutSQLPOINTER
266    for MaybeUninit<RefSQLHDESC<'conn, DT, V>>
267{
268    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
269        // Valid because RefSQLHDESC is a transparent newtype wrapper over RefUnsafeSQLHDESC
270        unsafe {
271            core::mem::transmute::<_, &mut MaybeUninit<RefUnsafeSQLHDESC<'conn, DT, V>>>(self)
272        }
273        .as_mut_SQLPOINTER()
274    }
275}
276
277unsafe impl AsSQLHANDLE for SQL_NULL_HANDLE {
278    fn as_SQLHANDLE(&self) -> SQLHANDLE {
279        core::ptr::null_mut()
280    }
281}
282unsafe impl<V: OdbcVersion> AsSQLHANDLE for SQLHENV<V> {
283    fn as_SQLHANDLE(&self) -> SQLHANDLE {
284        self.handle
285    }
286}
287unsafe impl<C: ConnState, V: OdbcVersion> AsSQLHANDLE for SQLHDBC<'_, C, V> {
288    fn as_SQLHANDLE(&self) -> SQLHANDLE {
289        self.handle
290    }
291}
292unsafe impl<V: OdbcVersion> AsSQLHANDLE for SQLHSTMT<'_, '_, '_, V> {
293    fn as_SQLHANDLE(&self) -> SQLHANDLE {
294        self.0.as_SQLHANDLE()
295    }
296}
297unsafe impl<V: OdbcVersion> AsSQLHANDLE for UnsafeSQLHSTMT<'_, '_, '_, V> {
298    fn as_SQLHANDLE(&self) -> SQLHANDLE {
299        self.handle
300    }
301}
302unsafe impl<V: OdbcVersion, T> AsSQLHANDLE for SQLHDESC<'_, T, V> {
303    fn as_SQLHANDLE(&self) -> SQLHANDLE {
304        self.0.as_SQLHANDLE()
305    }
306}
307unsafe impl<V: OdbcVersion, T> AsSQLHANDLE for UnsafeSQLHDESC<'_, T, V> {
308    fn as_SQLHANDLE(&self) -> SQLHANDLE {
309        self.handle
310    }
311}