odbc_api/buffers/item.rs
1use odbc_sys::{Date, Time, Timestamp};
2
3use super::{AnySlice, AnySliceMut, BufferDesc, NullableSlice, NullableSliceMut};
4use crate::Bit;
5
6/// Can either be extracted as a slice or a [`NullableSlice`] from an [`AnySlice`]. This allows
7/// the user to avoid matching on all possibile variants of an [`AnySlice`] in case the
8/// buffered type is known at compile time.
9///
10/// Usually used in generic code. E.g.:
11///
12/// ```
13/// use odbc_api::{Connection, buffers::Item};
14///
15/// fn insert_tuple2_vec<A: Item, B: Item>(
16/// conn: &Connection<'_>,
17/// insert_sql: &str,
18/// source: &[(A, B)],
19/// ) {
20/// let mut prepared = conn.prepare(insert_sql).unwrap();
21/// // Number of rows submitted in one round trip
22/// let capacity = source.len();
23/// // We do not need a nullable buffer since elements of source are not optional
24/// let descriptions = [A::buffer_desc(false), B::buffer_desc(false)];
25/// let mut inserter = prepared.column_inserter(capacity, descriptions).unwrap();
26/// // We send everything in one go.
27/// inserter.set_num_rows(source.len());
28/// // Now let's copy the row based tuple into the columnar structure
29/// for (index, (a, b)) in source.iter().enumerate() {
30/// inserter.column_mut(0).as_slice::<A>().unwrap()[index] = *a;
31/// inserter.column_mut(1).as_slice::<B>().unwrap()[index] = *b;
32/// }
33/// inserter.execute().unwrap();
34/// }
35/// ```
36pub trait Item: Sized + Copy {
37 /// Can be used to instantiate a [`super::ColumnarBuffer`]. This is useful to allocate the
38 /// correct buffers in generic code.
39 ///
40 /// # Example:
41 ///
42 /// Specification:
43 ///
44 /// ```
45 /// use odbc_api::buffers::{Item, BufferDesc};
46 ///
47 /// assert_eq!(BufferDesc::I64{ nullable: true }, i64::buffer_desc(true));
48 /// assert_eq!(BufferDesc::I64{ nullable: false }, i64::buffer_desc(false));
49 /// ```
50 fn buffer_desc(nullable: bool) -> BufferDesc;
51
52 /// Extract the array type from an [`AnySlice`].
53 fn as_slice(variant: AnySlice<'_>) -> Option<&[Self]>;
54 /// Extract the typed nullable buffer from an [`AnySlice`].
55 fn as_nullable_slice(variant: AnySlice<'_>) -> Option<NullableSlice<Self>>;
56
57 /// Extract the array type from an [`AnySliceMut`].
58 fn as_slice_mut(variant: AnySliceMut<'_>) -> Option<&'_ mut [Self]>;
59
60 /// Extract the typed nullable buffer from an [`AnySliceMut`].
61 fn as_nullable_slice_mut(variant: AnySliceMut<'_>) -> Option<NullableSliceMut<'_, Self>>;
62}
63
64macro_rules! impl_item {
65 ($t:ident, $plain:ident, $null:ident) => {
66 impl Item for $t {
67 fn buffer_desc(nullable: bool) -> BufferDesc {
68 BufferDesc::$plain { nullable }
69 }
70
71 fn as_slice(variant: AnySlice<'_>) -> Option<&[Self]> {
72 match variant {
73 AnySlice::$plain(vals) => Some(vals),
74 _ => None,
75 }
76 }
77
78 fn as_nullable_slice(variant: AnySlice<'_>) -> Option<NullableSlice<Self>> {
79 match variant {
80 AnySlice::$null(vals) => Some(vals),
81 _ => None,
82 }
83 }
84
85 fn as_slice_mut(variant: AnySliceMut<'_>) -> Option<&'_ mut [Self]> {
86 match variant {
87 AnySliceMut::$plain(vals) => Some(vals),
88 _ => None,
89 }
90 }
91
92 fn as_nullable_slice_mut(
93 variant: AnySliceMut<'_>,
94 ) -> Option<NullableSliceMut<'_, Self>> {
95 match variant {
96 AnySliceMut::$null(vals) => Some(vals),
97 _ => None,
98 }
99 }
100 }
101 };
102}
103
104impl_item!(f64, F64, NullableF64);
105impl_item!(f32, F32, NullableF32);
106impl_item!(u8, U8, NullableU8);
107impl_item!(i8, I8, NullableI8);
108impl_item!(i16, I16, NullableI16);
109impl_item!(i32, I32, NullableI32);
110impl_item!(i64, I64, NullableI64);
111impl_item!(Date, Date, NullableDate);
112impl_item!(Bit, Bit, NullableBit);
113impl_item!(Time, Time, NullableTime);
114impl_item!(Timestamp, Timestamp, NullableTimestamp);