rs_odbc/
attr.rs

1use crate::c_types::{CScalar, StrLenOrInd};
2use crate::convert::{AsMutPtr, AsMutSQLPOINTER, IntoSQLPOINTER};
3use crate::desc::AppDesc;
4use crate::env::OdbcVersion;
5use crate::handle::{RefSQLHDESC, RefUnsafeSQLHDESC, UnsafeSQLHDESC, SQLHDESC};
6use crate::str::{OdbcChar, OdbcStr};
7use crate::{
8    slice_len, Def, DriverDefined, Ident, OdbcDefined, Scalar, SQLCHAR, SQLINTEGER, SQLLEN,
9    SQLSMALLINT, SQLUINTEGER, SQLULEN, SQLUSMALLINT, SQLWCHAR,
10};
11use core::{cell::UnsafeCell, fmt::Debug, mem::MaybeUninit};
12
13pub unsafe trait Attr<A: Ident> {
14    type DefinedBy: Def;
15}
16pub unsafe trait AttrGet<A: Ident>: Attr<A> + AsMutSQLPOINTER + AttrZeroAssert {}
17pub unsafe trait AttrSet<A: Ident>: IntoSQLPOINTER + Sized {}
18
19// TODO: https://github.com/rust-lang/rust/issues/35121
20// Use never type ! when it is available on stable
21#[derive(Debug, Clone, Copy)]
22pub enum Void {}
23
24/// Same as [`AsMutPtr`] except that it's intended to be used to designate [`AttrLen::StrLen`] types.
25pub unsafe trait StrLen<T: Scalar> {
26    fn as_mut_ptr(&mut self) -> *mut T;
27}
28
29// TODO: https://github.com/rust-lang/rust/issues/20400
30// Once this problem is resolved, it would be possible to modify AttrLen<AD, LEN>
31// into AttrLen<A, LEN> and do more precise blanket implementations like
32// impl<T: Attr<A>, LEN> AttrLen<A, LEN> for T {}
33pub unsafe trait AttrLen<AD: Def, LEN: Scalar> {
34    /// Invariant: StrLen can only be LEN(for slices) or uninhabited type(for scalar types)
35    /// It is assumed that ODBC driver will never write to StrLen pointer for scalar types
36    type StrLen: StrLen<LEN>;
37
38    fn len(&self) -> LEN;
39}
40
41pub trait AttrZeroAssert {
42    fn assert_zeroed(&self) {}
43}
44
45// TODO: Implement and use for binary strings AttrLen
46//pub const fn SQL_LEN_BINARY_ATTR<LEN: OdbcInt>(length: LEN) {
47//    let SQL_LEN_BINARY_ATTR_OFFSET: LEN::new(-100);
48//    (-length).checked_add(SQL_LEN_BINARY_ATTR_OFFSET).expect()
49//}
50
51////////////////////////////////////////////////////////////////////////////////
52// GENERIC IMPLS
53////////////////////////////////////////////////////////////////////////////////
54
55unsafe impl<A: Ident, T: Scalar> Attr<A> for MaybeUninit<T>
56where
57    T: Attr<A> + AttrGet<A>,
58{
59    type DefinedBy = T::DefinedBy;
60}
61unsafe impl<A: Ident, T> Attr<A> for [MaybeUninit<T>]
62where
63    [T]: Attr<A> + AttrGet<A>,
64{
65    type DefinedBy = <[T] as Attr<A>>::DefinedBy;
66}
67unsafe impl<A: Ident> Attr<A> for OdbcStr<MaybeUninit<SQLCHAR>>
68where
69    OdbcStr<SQLCHAR>: Attr<A> + AttrGet<A>,
70{
71    type DefinedBy = <OdbcStr<SQLCHAR> as Attr<A>>::DefinedBy;
72}
73unsafe impl<A: Ident> Attr<A> for OdbcStr<MaybeUninit<SQLWCHAR>>
74where
75    OdbcStr<SQLWCHAR>: Attr<A> + AttrGet<A>,
76{
77    type DefinedBy = <OdbcStr<SQLWCHAR> as Attr<A>>::DefinedBy;
78}
79unsafe impl<A: Ident, T> Attr<A> for &[T]
80where
81    [T]: Attr<A>,
82{
83    type DefinedBy = <[T] as Attr<A>>::DefinedBy;
84}
85unsafe impl<A: Ident, CH: OdbcChar> Attr<A> for &OdbcStr<CH>
86where
87    OdbcStr<CH>: Attr<A>,
88{
89    type DefinedBy = <OdbcStr<CH> as Attr<A>>::DefinedBy;
90}
91
92unsafe impl<A: Ident, T: Scalar> AttrGet<A> for MaybeUninit<T>
93where
94    T: AttrGet<A>,
95    Self: AsMutSQLPOINTER,
96{
97}
98unsafe impl<A: Ident> AttrGet<A> for OdbcStr<MaybeUninit<SQLCHAR>> where OdbcStr<SQLCHAR>: AttrGet<A>
99{}
100unsafe impl<A: Ident> AttrGet<A> for OdbcStr<MaybeUninit<SQLWCHAR>> where
101    OdbcStr<SQLWCHAR>: AttrGet<A>
102{
103}
104
105unsafe impl<A: Ident, T: Scalar> AttrSet<A> for MaybeUninit<T>
106where
107    Self: IntoSQLPOINTER,
108    T: AttrSet<A>,
109{
110}
111
112unsafe impl<AD: Def, T: Ident, LEN: Scalar> AttrLen<AD, LEN> for T
113where
114    MaybeUninit<T>: AttrLen<AD, LEN>,
115    LEN: From<SQLSMALLINT>,
116{
117    type StrLen = Void;
118
119    fn len(&self) -> LEN {
120        // Transmute is safe because MaybeUninit<T> has the same size and alignment as T
121        <MaybeUninit<_> as AttrLen<AD, LEN>>::len(unsafe { core::mem::transmute(self) })
122    }
123}
124unsafe impl<T: Ident, LEN: Scalar> AttrLen<OdbcDefined, LEN> for MaybeUninit<T>
125where
126    LEN: From<SQLSMALLINT>,
127{
128    type StrLen = Void;
129
130    fn len(&self) -> LEN {
131        LEN::from(0)
132    }
133}
134unsafe impl<T: Ident, LEN: Scalar> AttrLen<DriverDefined, LEN> for MaybeUninit<T>
135where
136    LEN: From<T::Type>,
137{
138    type StrLen = Void;
139
140    fn len(&self) -> LEN {
141        LEN::from(T::IDENTIFIER)
142    }
143}
144unsafe impl<AD: Def, CH: OdbcChar, LEN: Scalar> AttrLen<AD, LEN> for OdbcStr<CH>
145where
146    LEN: TryFrom<usize>,
147    LEN::Error: Debug,
148    OdbcStr<MaybeUninit<CH>>: AttrLen<AD, LEN>,
149{
150    type StrLen = <OdbcStr<MaybeUninit<CH>> as AttrLen<AD, LEN>>::StrLen;
151
152    fn len(&self) -> LEN {
153        // Transmute is safe because MaybeUninit<T> has the same size and alignment as T
154        <OdbcStr<MaybeUninit<CH>> as AttrLen<AD, LEN>>::len(unsafe { core::mem::transmute(self) })
155    }
156}
157unsafe impl<AD: Def, CH: OdbcChar, LEN: Scalar> AttrLen<AD, LEN> for OdbcStr<MaybeUninit<CH>>
158where
159    LEN: TryFrom<usize> + core::ops::Mul<Output = LEN>,
160    LEN::Error: Debug,
161{
162    type StrLen = LEN;
163
164    fn len(&self) -> LEN {
165        // TODO: Check for multiplication overflow with checked_mul
166        slice_len::<_, LEN>(self) * LEN::try_from(core::mem::size_of::<CH>()).unwrap()
167    }
168}
169// TODO: If this is a deferred buffer, then I believe len should be 0
170// This can be resolved with specialization by having special implementation for SQL_DESC_DATA_PTR
171// and alike if there are other attributes that correspond to deferred buffers
172unsafe impl<LEN: Scalar> AttrLen<OdbcDefined, LEN> for [MaybeUninit<SQLCHAR>]
173where
174    LEN: TryFrom<usize>,
175    LEN::Error: Debug,
176{
177    type StrLen = LEN;
178
179    fn len(&self) -> LEN {
180        slice_len(self)
181    }
182}
183// TODO: What if this is a deferred buffer, then I believe len should be 0
184// This can be resolved with specialization by having special implementation for SQL_DESC_DATA_PTR
185// and alike if there are other attributes that correspond to deferred buffers
186unsafe impl<LEN: Scalar> AttrLen<DriverDefined, LEN> for [MaybeUninit<SQLCHAR>] {
187    type StrLen = LEN;
188
189    fn len(&self) -> LEN {
190        // TODO: Should be a negative value
191        unimplemented!();
192    }
193}
194unsafe impl<AD: Def, LEN: Scalar> AttrLen<AD, LEN> for [SQLCHAR]
195where
196    [MaybeUninit<SQLCHAR>]: AttrLen<AD, LEN>,
197{
198    type StrLen = <[MaybeUninit<SQLCHAR>] as AttrLen<AD, LEN>>::StrLen;
199
200    fn len(&self) -> LEN {
201        // Transmute is safe because MaybeUninit<T> has the same size and alignment as T
202        <[MaybeUninit<SQLCHAR>] as AttrLen<AD, LEN>>::len(unsafe { core::mem::transmute(self) })
203    }
204}
205unsafe impl<AD: Def, T: Ident, LEN: Scalar> AttrLen<AD, LEN> for [T]
206where
207    LEN: From<SQLSMALLINT>,
208{
209    type StrLen = Void;
210
211    fn len(&self) -> LEN {
212        LEN::from(0)
213    }
214}
215unsafe impl<AD: Def, LEN: Scalar, CH: OdbcChar> AttrLen<AD, LEN> for &OdbcStr<CH>
216where
217    OdbcStr<CH>: AttrLen<AD, LEN>,
218{
219    type StrLen = <OdbcStr<CH> as AttrLen<AD, LEN>>::StrLen;
220
221    fn len(&self) -> LEN {
222        AttrLen::len(*self)
223    }
224}
225unsafe impl<AD: Def, LEN: Scalar, T> AttrLen<AD, LEN> for &[T]
226where
227    [T]: AttrLen<AD, LEN>,
228{
229    type StrLen = <[T] as AttrLen<AD, LEN>>::StrLen;
230
231    fn len(&self) -> LEN {
232        AttrLen::len(*self)
233    }
234}
235// Deferred buffers are used only through SQLSetDescAttr and SQLGetDescAttr
236unsafe impl<AD: Def, T: CScalar> AttrLen<AD, SQLINTEGER> for UnsafeCell<T> {
237    type StrLen = Void;
238
239    fn len(&self) -> SQLINTEGER {
240        0
241    }
242}
243// Deferred buffers are used only through SQLSetDescAttr and SQLGetDescAttr
244unsafe impl<AD: Def, T> AttrLen<AD, SQLINTEGER> for [UnsafeCell<T>] {
245    type StrLen = Void;
246
247    fn len(&self) -> SQLINTEGER {
248        0 // Length is not used for deferred buffers
249    }
250}
251unsafe impl<DT, LEN: Scalar, V: OdbcVersion> AttrLen<OdbcDefined, LEN>
252    for MaybeUninit<RefUnsafeSQLHDESC<'_, DT, V>>
253where
254    LEN: From<SQLSMALLINT>,
255{
256    type StrLen = Void;
257
258    fn len(&self) -> LEN {
259        LEN::from(0)
260    }
261}
262unsafe impl<DT, LEN: Scalar, V: OdbcVersion> AttrLen<DriverDefined, LEN>
263    for MaybeUninit<RefUnsafeSQLHDESC<'_, DT, V>>
264where
265    LEN: From<SQLSMALLINT>,
266{
267    type StrLen = Void;
268
269    fn len(&self) -> LEN {
270        LEN::from(crate::SQL_IS_POINTER)
271    }
272}
273unsafe impl<'conn, AD: Def, DT, LEN: Scalar, V: OdbcVersion> AttrLen<AD, LEN>
274    for MaybeUninit<RefSQLHDESC<'conn, DT, V>>
275where
276    MaybeUninit<RefUnsafeSQLHDESC<'conn, DT, V>>: AttrLen<AD, LEN>,
277    LEN: From<SQLSMALLINT>,
278{
279    type StrLen = <MaybeUninit<RefUnsafeSQLHDESC<'conn, DT, V>> as AttrLen<AD, LEN>>::StrLen;
280
281    fn len(&self) -> LEN {
282        // Transmute is safe because RefSQLHDESC is a transparent wrapper over RefUnsafeSQLHDESC
283        unsafe { core::mem::transmute::<_, &MaybeUninit<RefUnsafeSQLHDESC<'conn, DT, V>>>(self) }
284            .len()
285    }
286}
287unsafe impl<LEN: Scalar, V: OdbcVersion> AttrLen<OdbcDefined, LEN>
288    for Option<&UnsafeSQLHDESC<'_, AppDesc<'_>, V>>
289where
290    LEN: From<SQLSMALLINT>,
291{
292    type StrLen = Void;
293
294    fn len(&self) -> LEN {
295        LEN::from(0)
296    }
297}
298unsafe impl<LEN: Scalar, V: OdbcVersion> AttrLen<DriverDefined, LEN>
299    for Option<&UnsafeSQLHDESC<'_, AppDesc<'_>, V>>
300where
301    LEN: From<SQLSMALLINT>,
302{
303    type StrLen = Void;
304
305    fn len(&self) -> LEN {
306        LEN::from(crate::SQL_IS_POINTER)
307    }
308}
309unsafe impl<'a, 'conn, 'buf, AD: Def, LEN: Scalar, V: OdbcVersion> AttrLen<AD, LEN>
310    for Option<&'a SQLHDESC<'conn, AppDesc<'buf>, V>>
311where
312    Option<&'a UnsafeSQLHDESC<'conn, AppDesc<'buf>, V>>: AttrLen<AD, LEN>,
313    LEN: From<SQLSMALLINT>,
314{
315    type StrLen = <Option<&'a UnsafeSQLHDESC<'conn, AppDesc<'buf>, V>> as AttrLen<AD, LEN>>::StrLen;
316
317    fn len(&self) -> LEN {
318        // Transmute is safe because SQLHDESC is a transparent wrapper over UnsafeSQLHDESC
319        unsafe { core::mem::transmute::<_, Option<&UnsafeSQLHDESC<'conn, AppDesc<'buf>, V>>>(self) }
320            .len()
321    }
322}
323
324unsafe impl<T: Scalar> StrLen<T> for T
325where
326    T: AsMutPtr<T>,
327{
328    fn as_mut_ptr(&mut self) -> *mut T {
329        <Self as AsMutPtr<T>>::as_mut_ptr(self)
330    }
331}
332unsafe impl<T: Scalar> StrLen<T> for MaybeUninit<T>
333where
334    Self: AsMutPtr<T>,
335    T: StrLen<T>,
336{
337    fn as_mut_ptr(&mut self) -> *mut T {
338        <Self as AsMutPtr<T>>::as_mut_ptr(self)
339    }
340}
341
342impl<T> AttrZeroAssert for MaybeUninit<T> {
343    // MaybeUninit must not be read
344}
345impl<T> AttrZeroAssert for [T] {}
346impl<T> AttrZeroAssert for OdbcStr<T> {}
347impl<T: CScalar> AttrZeroAssert for UnsafeCell<T> {
348    // Deferred buffers don't need to be zeroed
349}
350
351////////////////////////////////////////////////////////////////////////////////
352// CONCRETE IMPLS
353////////////////////////////////////////////////////////////////////////////////
354
355// TODO: Why are these needed?
356unsafe impl StrLen<SQLLEN> for MaybeUninit<StrLenOrInd> {
357    fn as_mut_ptr(&mut self) -> *mut SQLLEN {
358        self.as_mut_ptr().cast()
359    }
360}
361unsafe impl StrLen<SQLLEN> for UnsafeCell<StrLenOrInd> {
362    fn as_mut_ptr(&mut self) -> *mut SQLLEN {
363        self.get().cast()
364    }
365}
366unsafe impl<T: Scalar> StrLen<T> for Void {
367    fn as_mut_ptr(&mut self) -> *mut T {
368        // Uninhabited type has no memory location
369        core::ptr::null_mut()
370    }
371}
372unsafe impl<T: Scalar> StrLen<T> for MaybeUninit<Void> {
373    fn as_mut_ptr(&mut self) -> *mut T {
374        // Uninhabited type has no memory location
375        core::ptr::null_mut()
376    }
377}
378
379impl AttrZeroAssert for SQLSMALLINT {
380    fn assert_zeroed(&self) {
381        // TODO: Add custom message
382        assert_eq!(0, *self);
383    }
384}
385impl AttrZeroAssert for SQLUSMALLINT {
386    fn assert_zeroed(&self) {
387        // TODO: Add custom message
388        assert_eq!(0, *self);
389    }
390}
391impl AttrZeroAssert for SQLINTEGER {
392    fn assert_zeroed(&self) {
393        // TODO: Add custom message
394        assert_eq!(0, *self);
395    }
396}
397impl AttrZeroAssert for SQLUINTEGER {
398    fn assert_zeroed(&self) {
399        // TODO: Add custom message
400        assert_eq!(0, *self);
401    }
402}
403impl AttrZeroAssert for SQLLEN {
404    fn assert_zeroed(&self) {
405        // TODO: Add custom message
406        assert_eq!(0, *self);
407    }
408}
409impl AttrZeroAssert for SQLULEN {
410    fn assert_zeroed(&self) {
411        // TODO: Add custom message
412        assert_eq!(0, *self);
413    }
414}