odbc_api/
nullable.rs

1use std::ffi::c_void;
2
3use odbc_sys::NULL_DATA;
4
5use crate::{
6    buffers::{FetchRowMember, Indicator},
7    fixed_sized::Pod,
8    handles::{CData, CDataMut, HasDataType},
9    parameter::CElement,
10    OutputParameter,
11};
12
13/// Wraps a type T together with an additional indicator. This way the type gains a Null
14/// representation, those memory layout is compatible with ODBC.
15#[derive(Clone, Copy)]
16pub struct Nullable<T> {
17    indicator: isize,
18    value: T,
19}
20
21impl<T> Nullable<T> {
22    pub fn new(value: T) -> Self {
23        Self {
24            indicator: 0,
25            value,
26        }
27    }
28
29    pub fn null() -> Self
30    where
31        T: Default,
32    {
33        Self {
34            indicator: NULL_DATA,
35            value: Default::default(),
36        }
37    }
38
39    pub fn as_opt(&self) -> Option<&T> {
40        if self.indicator == NULL_DATA {
41            None
42        } else {
43            Some(&self.value)
44        }
45    }
46
47    pub fn into_opt(self) -> Option<T> {
48        if self.indicator == NULL_DATA {
49            None
50        } else {
51            Some(self.value)
52        }
53    }
54}
55
56impl<T> Default for Nullable<T>
57where
58    T: Default,
59{
60    fn default() -> Self {
61        Self::null()
62    }
63}
64
65unsafe impl<T> CData for Nullable<T>
66where
67    T: Pod,
68{
69    fn cdata_type(&self) -> odbc_sys::CDataType {
70        self.value.cdata_type()
71    }
72
73    fn indicator_ptr(&self) -> *const isize {
74        &self.indicator as *const isize
75    }
76
77    fn value_ptr(&self) -> *const c_void {
78        self.value.value_ptr()
79    }
80
81    fn buffer_length(&self) -> isize {
82        0
83    }
84}
85
86impl<T> HasDataType for Nullable<T>
87where
88    T: Pod + HasDataType,
89{
90    fn data_type(&self) -> crate::DataType {
91        self.value.data_type()
92    }
93}
94
95unsafe impl<T> CElement for Nullable<T>
96where
97    T: Pod,
98{
99    /// Does nothing. `T` is fixed size and therfore always complete.
100    fn assert_completness(&self) {}
101}
102
103unsafe impl<T> CDataMut for Nullable<T>
104where
105    T: Pod,
106{
107    fn mut_indicator_ptr(&mut self) -> *mut isize {
108        &mut self.indicator as *mut isize
109    }
110
111    fn mut_value_ptr(&mut self) -> *mut c_void {
112        &mut self.value as *mut T as *mut c_void
113    }
114}
115
116unsafe impl<T> OutputParameter for Nullable<T> where T: Pod + HasDataType {}
117
118unsafe impl<T> FetchRowMember for Nullable<T>
119where
120    T: Pod,
121{
122    fn indicator(&self) -> Option<crate::buffers::Indicator> {
123        Some(Indicator::from_isize(self.indicator))
124    }
125}