odbc_api/buffers/
item.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use odbc_sys::{Date, Time, Timestamp};

use super::{AnySlice, AnySliceMut, BufferDesc, NullableSlice, NullableSliceMut};
use crate::Bit;

/// Can either be extracted as a slice or a [`NullableSlice`] from an [`AnySlice`]. This allows
/// the user to avoid matching on all possibile variants of an [`AnySlice`] in case the
/// buffered type is known at compile time.
///
/// Usually used in generic code. E.g.:
///
/// ```
/// use odbc_api::{Connection, buffers::Item};
///
/// fn insert_tuple2_vec<A: Item, B: Item>(
///     conn: &Connection<'_>,
///     insert_sql: &str,
///     source: &[(A, B)],
/// ) {
///     let mut prepared = conn.prepare(insert_sql).unwrap();
///     // Number of rows submitted in one round trip
///     let capacity = source.len();
///     // We do not need a nullable buffer since elements of source are not optional
///     let descriptions = [A::buffer_desc(false), B::buffer_desc(false)];
///     let mut inserter = prepared.column_inserter(capacity, descriptions).unwrap();
///     // We send everything in one go.
///     inserter.set_num_rows(source.len());
///     // Now let's copy the row based tuple into the columnar structure
///     for (index, (a, b)) in source.iter().enumerate() {
///         inserter.column_mut(0).as_slice::<A>().unwrap()[index] = *a;
///         inserter.column_mut(1).as_slice::<B>().unwrap()[index] = *b;
///     }
///     inserter.execute().unwrap();
/// }
/// ```
pub trait Item: Sized + Copy {
    /// Can be used to instantiate a [`super::ColumnarBuffer`]. This is useful to allocate the
    /// correct buffers in generic code.
    ///
    /// # Example:
    ///
    /// Specification:
    ///
    /// ```
    /// use odbc_api::buffers::{Item, BufferDesc};
    ///
    /// assert_eq!(BufferDesc::I64{ nullable: true }, i64::buffer_desc(true));
    /// assert_eq!(BufferDesc::I64{ nullable: false }, i64::buffer_desc(false));
    /// ```
    fn buffer_desc(nullable: bool) -> BufferDesc;

    /// Extract the array type from an [`AnySlice`].
    fn as_slice(variant: AnySlice<'_>) -> Option<&[Self]>;
    /// Extract the typed nullable buffer from an [`AnySlice`].
    fn as_nullable_slice(variant: AnySlice<'_>) -> Option<NullableSlice<Self>>;

    /// Extract the array type from an [`AnySliceMut`].
    fn as_slice_mut(variant: AnySliceMut<'_>) -> Option<&'_ mut [Self]>;

    /// Extract the typed nullable buffer from an [`AnySliceMut`].
    fn as_nullable_slice_mut(variant: AnySliceMut<'_>) -> Option<NullableSliceMut<'_, Self>>;
}

macro_rules! impl_item {
    ($t:ident, $plain:ident, $null:ident) => {
        impl Item for $t {
            fn buffer_desc(nullable: bool) -> BufferDesc {
                BufferDesc::$plain { nullable }
            }

            fn as_slice(variant: AnySlice<'_>) -> Option<&[Self]> {
                match variant {
                    AnySlice::$plain(vals) => Some(vals),
                    _ => None,
                }
            }

            fn as_nullable_slice(variant: AnySlice<'_>) -> Option<NullableSlice<Self>> {
                match variant {
                    AnySlice::$null(vals) => Some(vals),
                    _ => None,
                }
            }

            fn as_slice_mut(variant: AnySliceMut<'_>) -> Option<&'_ mut [Self]> {
                match variant {
                    AnySliceMut::$plain(vals) => Some(vals),
                    _ => None,
                }
            }

            fn as_nullable_slice_mut(
                variant: AnySliceMut<'_>,
            ) -> Option<NullableSliceMut<'_, Self>> {
                match variant {
                    AnySliceMut::$null(vals) => Some(vals),
                    _ => None,
                }
            }
        }
    };
}

impl_item!(f64, F64, NullableF64);
impl_item!(f32, F32, NullableF32);
impl_item!(u8, U8, NullableU8);
impl_item!(i8, I8, NullableI8);
impl_item!(i16, I16, NullableI16);
impl_item!(i32, I32, NullableI32);
impl_item!(i64, I64, NullableI64);
impl_item!(Date, Date, NullableDate);
impl_item!(Bit, Bit, NullableBit);
impl_item!(Time, Time, NullableTime);
impl_item!(Timestamp, Timestamp, NullableTimestamp);