odbc_api/buffers/
any_buffer.rs

1use std::{collections::HashSet, ffi::c_void};
2
3use odbc_sys::{CDataType, Date, Numeric, Time, Timestamp};
4
5use crate::{
6    Bit, DataType, Error,
7    buffers::columnar::Resize,
8    columnar_bulk_inserter::BoundInputSlice,
9    error::TooLargeBufferSize,
10    handles::{CData, CDataMut, HasDataType, StatementRef},
11    parameter::WithDataType,
12};
13
14use super::{
15    BinColumn, BinColumnView, BufferDesc, CharColumn, ColumnarBuffer, Indicator, Item,
16    NullableSlice, NullableSliceMut, TextColumn, TextColumnView, WCharColumn,
17    bin_column::BinColumnSliceMut,
18    column_with_indicator::{
19        OptBitColumn, OptDateColumn, OptF32Column, OptF64Column, OptI8Column, OptI16Column,
20        OptI32Column, OptI64Column, OptTimeColumn, OptTimestampColumn, OptU8Column,
21    },
22    columnar::ColumnBuffer,
23    text_column::TextColumnSliceMut,
24};
25
26/// Since buffer shapes are the same for all time/timestamp types independent of the precision and
27/// we do not know the precise SQL type. In order to still be able to bind time/timestamp buffers as
28/// input without requiring the user to separately specify the precision, we declare 100 nanosecond
29/// precision. This was the highest precision still supported by MSSQL in the tests.
30const DEFAULT_TIME_PRECISION: i16 = 7;
31
32/// Buffer holding a single column of either a result set or parameter
33#[derive(Debug)]
34pub enum AnyBuffer {
35    /// A buffer for holding both nullable and required binary data.
36    Binary(BinColumn),
37    /// A buffer for holding both nullable and required text data. Uses the system encoding for
38    /// character data.
39    Text(CharColumn),
40    /// A buffer for holding both nullable and required text data. Uses UTF-16 encoding
41    WText(WCharColumn),
42    Date(Vec<Date>),
43    Time(Vec<Time>),
44    Timestamp(Vec<Timestamp>),
45    F64(Vec<f64>),
46    F32(Vec<f32>),
47    I8(Vec<i8>),
48    I16(Vec<i16>),
49    I32(Vec<i32>),
50    I64(Vec<i64>),
51    U8(Vec<u8>),
52    Bit(Vec<Bit>),
53    Numeric(WithDataType<Vec<Numeric>>),
54    NullableDate(OptDateColumn),
55    NullableTime(OptTimeColumn),
56    NullableTimestamp(OptTimestampColumn),
57    NullableF64(OptF64Column),
58    NullableF32(OptF32Column),
59    NullableI8(OptI8Column),
60    NullableI16(OptI16Column),
61    NullableI32(OptI32Column),
62    NullableI64(OptI64Column),
63    NullableU8(OptU8Column),
64    NullableBit(OptBitColumn),
65}
66
67impl AnyBuffer {
68    /// Map buffer description to actual buffer.
69    pub fn try_from_desc(max_rows: usize, desc: BufferDesc) -> Result<Self, TooLargeBufferSize> {
70        let fallible_allocations = true;
71        Self::impl_from_desc(max_rows, desc, fallible_allocations)
72    }
73
74    /// Map buffer description to actual buffer.
75    pub fn from_desc(max_rows: usize, desc: BufferDesc) -> Self {
76        let fallible_allocations = false;
77        Self::impl_from_desc(max_rows, desc, fallible_allocations).unwrap()
78    }
79
80    /// Map buffer description to actual buffer.
81    fn impl_from_desc(
82        max_rows: usize,
83        desc: BufferDesc,
84        fallible_allocations: bool,
85    ) -> Result<Self, TooLargeBufferSize> {
86        let buffer = match desc {
87            BufferDesc::Binary { length } => {
88                if fallible_allocations {
89                    AnyBuffer::Binary(BinColumn::try_new(max_rows, length)?)
90                } else {
91                    AnyBuffer::Binary(BinColumn::new(max_rows, length))
92                }
93            }
94            BufferDesc::Text { max_str_len } => {
95                if fallible_allocations {
96                    AnyBuffer::Text(TextColumn::try_new(max_rows, max_str_len)?)
97                } else {
98                    AnyBuffer::Text(TextColumn::new(max_rows, max_str_len))
99                }
100            }
101            BufferDesc::WText { max_str_len } => {
102                if fallible_allocations {
103                    AnyBuffer::WText(TextColumn::try_new(max_rows, max_str_len)?)
104                } else {
105                    AnyBuffer::WText(TextColumn::new(max_rows, max_str_len))
106                }
107            }
108            BufferDesc::Date { nullable: false } => {
109                AnyBuffer::Date(vec![Date::default(); max_rows])
110            }
111            BufferDesc::Time { nullable: false } => {
112                AnyBuffer::Time(vec![Time::default(); max_rows])
113            }
114            BufferDesc::Timestamp { nullable: false } => {
115                AnyBuffer::Timestamp(vec![Timestamp::default(); max_rows])
116            }
117            BufferDesc::F64 { nullable: false } => AnyBuffer::F64(vec![f64::default(); max_rows]),
118            BufferDesc::F32 { nullable: false } => AnyBuffer::F32(vec![f32::default(); max_rows]),
119            BufferDesc::I8 { nullable: false } => AnyBuffer::I8(vec![i8::default(); max_rows]),
120            BufferDesc::I16 { nullable: false } => AnyBuffer::I16(vec![i16::default(); max_rows]),
121            BufferDesc::I32 { nullable: false } => AnyBuffer::I32(vec![i32::default(); max_rows]),
122            BufferDesc::I64 { nullable: false } => AnyBuffer::I64(vec![i64::default(); max_rows]),
123            BufferDesc::U8 { nullable: false } => AnyBuffer::U8(vec![u8::default(); max_rows]),
124            BufferDesc::Bit { nullable: false } => AnyBuffer::Bit(vec![Bit::default(); max_rows]),
125            BufferDesc::Numeric { precision, scale } => AnyBuffer::Numeric(WithDataType::new(
126                vec![Numeric::default(); max_rows],
127                DataType::Numeric { precision, scale },
128            )),
129            BufferDesc::Date { nullable: true } => {
130                AnyBuffer::NullableDate(OptDateColumn::new(max_rows))
131            }
132            BufferDesc::Time { nullable: true } => {
133                AnyBuffer::NullableTime(OptTimeColumn::new(max_rows))
134            }
135            BufferDesc::Timestamp { nullable: true } => {
136                AnyBuffer::NullableTimestamp(OptTimestampColumn::new(max_rows))
137            }
138            BufferDesc::F64 { nullable: true } => {
139                AnyBuffer::NullableF64(OptF64Column::new(max_rows))
140            }
141            BufferDesc::F32 { nullable: true } => {
142                AnyBuffer::NullableF32(OptF32Column::new(max_rows))
143            }
144            BufferDesc::I8 { nullable: true } => AnyBuffer::NullableI8(OptI8Column::new(max_rows)),
145            BufferDesc::I16 { nullable: true } => {
146                AnyBuffer::NullableI16(OptI16Column::new(max_rows))
147            }
148            BufferDesc::I32 { nullable: true } => {
149                AnyBuffer::NullableI32(OptI32Column::new(max_rows))
150            }
151            BufferDesc::I64 { nullable: true } => {
152                AnyBuffer::NullableI64(OptI64Column::new(max_rows))
153            }
154            BufferDesc::U8 { nullable: true } => AnyBuffer::NullableU8(OptU8Column::new(max_rows)),
155            BufferDesc::Bit { nullable: true } => {
156                AnyBuffer::NullableBit(OptBitColumn::new(max_rows))
157            }
158        };
159        Ok(buffer)
160    }
161
162    fn inner(&self) -> &dyn CData {
163        match self {
164            AnyBuffer::Binary(col) => col,
165            AnyBuffer::Text(col) => col,
166            AnyBuffer::WText(col) => col,
167            AnyBuffer::F64(col) => col,
168            AnyBuffer::F32(col) => col,
169            AnyBuffer::Date(col) => col,
170            AnyBuffer::Time(col) => col,
171            AnyBuffer::Timestamp(col) => col,
172            AnyBuffer::I8(col) => col,
173            AnyBuffer::I16(col) => col,
174            AnyBuffer::I32(col) => col,
175            AnyBuffer::I64(col) => col,
176            AnyBuffer::Bit(col) => col,
177            AnyBuffer::U8(col) => col,
178            AnyBuffer::Numeric(col) => col,
179            AnyBuffer::NullableF64(col) => col,
180            AnyBuffer::NullableF32(col) => col,
181            AnyBuffer::NullableDate(col) => col,
182            AnyBuffer::NullableTime(col) => col,
183            AnyBuffer::NullableTimestamp(col) => col,
184            AnyBuffer::NullableI8(col) => col,
185            AnyBuffer::NullableI16(col) => col,
186            AnyBuffer::NullableI32(col) => col,
187            AnyBuffer::NullableI64(col) => col,
188            AnyBuffer::NullableBit(col) => col,
189            AnyBuffer::NullableU8(col) => col,
190        }
191    }
192
193    fn inner_mut(&mut self) -> &mut dyn AnyBufferVariantMut {
194        match self {
195            AnyBuffer::Binary(col) => col,
196            AnyBuffer::Text(col) => col,
197            AnyBuffer::WText(col) => col,
198            AnyBuffer::F64(col) => col,
199            AnyBuffer::F32(col) => col,
200            AnyBuffer::Date(col) => col,
201            AnyBuffer::Time(col) => col,
202            AnyBuffer::Timestamp(col) => col,
203            AnyBuffer::I8(col) => col,
204            AnyBuffer::I16(col) => col,
205            AnyBuffer::I32(col) => col,
206            AnyBuffer::I64(col) => col,
207            AnyBuffer::Bit(col) => col,
208            AnyBuffer::U8(col) => col,
209            AnyBuffer::Numeric(col) => &mut col.value,
210            AnyBuffer::NullableF64(col) => col,
211            AnyBuffer::NullableF32(col) => col,
212            AnyBuffer::NullableDate(col) => col,
213            AnyBuffer::NullableTime(col) => col,
214            AnyBuffer::NullableTimestamp(col) => col,
215            AnyBuffer::NullableI8(col) => col,
216            AnyBuffer::NullableI16(col) => col,
217            AnyBuffer::NullableI32(col) => col,
218            AnyBuffer::NullableI64(col) => col,
219            AnyBuffer::NullableBit(col) => col,
220            AnyBuffer::NullableU8(col) => col,
221        }
222    }
223}
224
225/// A trait implemented by all variants of [`AnyBuffer`]. This allows us to reduce the number of
226/// match statements for methods mutating [`AnyBuffer`], as we only need to implement
227/// [`AnyBuffer::inner_mut`].
228trait AnyBufferVariantMut: CDataMut + Resize {}
229
230impl<T> AnyBufferVariantMut for T where T: CDataMut + Resize {}
231
232unsafe impl CData for AnyBuffer {
233    fn cdata_type(&self) -> CDataType {
234        self.inner().cdata_type()
235    }
236
237    fn indicator_ptr(&self) -> *const isize {
238        self.inner().indicator_ptr()
239    }
240
241    fn value_ptr(&self) -> *const c_void {
242        self.inner().value_ptr()
243    }
244
245    fn buffer_length(&self) -> isize {
246        self.inner().buffer_length()
247    }
248}
249
250unsafe impl CDataMut for AnyBuffer {
251    fn mut_indicator_ptr(&mut self) -> *mut isize {
252        self.inner_mut().mut_indicator_ptr()
253    }
254
255    fn mut_value_ptr(&mut self) -> *mut c_void {
256        self.inner_mut().mut_value_ptr()
257    }
258}
259
260impl HasDataType for AnyBuffer {
261    fn data_type(&self) -> DataType {
262        match self {
263            AnyBuffer::Binary(col) => col.data_type(),
264            AnyBuffer::Text(col) => col.data_type(),
265            AnyBuffer::WText(col) => col.data_type(),
266            AnyBuffer::Date(_) | AnyBuffer::NullableDate(_) => DataType::Date,
267            AnyBuffer::Time(_) | AnyBuffer::NullableTime(_) => DataType::Time {
268                precision: DEFAULT_TIME_PRECISION,
269            },
270            AnyBuffer::Timestamp(_) | AnyBuffer::NullableTimestamp(_) => DataType::Timestamp {
271                precision: DEFAULT_TIME_PRECISION,
272            },
273            AnyBuffer::F64(_) | AnyBuffer::NullableF64(_) => DataType::Double,
274            AnyBuffer::F32(_) | AnyBuffer::NullableF32(_) => DataType::Real,
275            AnyBuffer::I8(_) | AnyBuffer::NullableI8(_) => DataType::TinyInt,
276            AnyBuffer::I16(_) | AnyBuffer::NullableI16(_) => DataType::SmallInt,
277            AnyBuffer::I32(_) | AnyBuffer::NullableI32(_) => DataType::Integer,
278            AnyBuffer::I64(_) | AnyBuffer::NullableI64(_) => DataType::BigInt,
279            // Few databases support unsigned types, binding U8 as tiny int might lead to weird
280            // stuff if the database has type is signed. I guess. Let's bind it as SmallInt by
281            // default, just to be on the safe side.
282            AnyBuffer::U8(_) | AnyBuffer::NullableU8(_) => DataType::SmallInt,
283            AnyBuffer::Bit(_) | AnyBuffer::NullableBit(_) => DataType::Bit,
284            AnyBuffer::Numeric(col) => col.data_type(),
285        }
286    }
287}
288
289/// Flexible columnar buffer implementation. Bind this to a cursor to fetch values in bulk, or pass
290/// this as a parameter to a statement, to submit many parameters at once.
291pub type ColumnarAnyBuffer = ColumnarBuffer<AnyBuffer>;
292
293impl ColumnarAnyBuffer {
294    /// Allocates a [`ColumnarBuffer`] fitting the buffer descriptions.
295    pub fn from_descs(capacity: usize, descs: impl IntoIterator<Item = BufferDesc>) -> Self {
296        let mut column_index = 0;
297        let columns = descs
298            .into_iter()
299            .map(move |desc| {
300                let buffer = AnyBuffer::from_desc(capacity, desc);
301                column_index += 1;
302                (column_index, buffer)
303            })
304            .collect();
305        unsafe { ColumnarBuffer::new_unchecked(capacity, columns) }
306    }
307
308    /// Allocates a [`ColumnarBuffer`] fitting the buffer descriptions. If not enough memory is
309    /// available to allocate the buffers this function fails with
310    /// [`Error::TooLargeColumnBufferSize`]. This function is slower than [`Self::from_descs`]
311    /// which would just panic if not enough memory is available for allocation.
312    pub fn try_from_descs(
313        capacity: usize,
314        descs: impl IntoIterator<Item = BufferDesc>,
315    ) -> Result<Self, Error> {
316        let mut column_index = 0;
317        let columns = descs
318            .into_iter()
319            .map(move |desc| {
320                let buffer = AnyBuffer::try_from_desc(capacity, desc)
321                    .map_err(|source| source.add_context(column_index))?;
322                column_index += 1;
323                Ok::<_, Error>((column_index, buffer))
324            })
325            .collect::<Result<_, _>>()?;
326        Ok(unsafe { ColumnarBuffer::new_unchecked(capacity, columns) })
327    }
328
329    /// Allows you to pass the buffer descriptions together with a one based column index referring
330    /// the column, the buffer is supposed to bind to. This allows you also to ignore columns in a
331    /// result set, by not binding them at all. There is no restriction on the order of column
332    /// indices passed, but the function will panic, if the indices are not unique.
333    pub fn from_descs_and_indices(
334        max_rows: usize,
335        description: impl Iterator<Item = (u16, BufferDesc)>,
336    ) -> ColumnarBuffer<AnyBuffer> {
337        let columns: Vec<_> = description
338            .map(|(col_index, buffer_desc)| {
339                (col_index, AnyBuffer::from_desc(max_rows, buffer_desc))
340            })
341            .collect();
342
343        // Assert uniqueness of indices
344        let mut indices = HashSet::new();
345        if columns
346            .iter()
347            .any(move |&(col_index, _)| !indices.insert(col_index))
348        {
349            panic!("Column indices must be unique.")
350        }
351
352        ColumnarBuffer::new(columns)
353    }
354}
355
356/// A borrowed view on the valid rows in a column of a [`crate::buffers::ColumnarBuffer`].
357///
358/// For columns of fixed size types, which are guaranteed to not contain null, a direct access to
359/// the slice is offered. Buffers over nullable columns can be accessed via an iterator over
360/// options.
361#[derive(Debug, Clone, Copy)]
362pub enum AnySlice<'a> {
363    /// Nullable character data in the system encoding.
364    Text(TextColumnView<'a, u8>),
365    /// Nullable character data encoded in UTF-16.
366    WText(TextColumnView<'a, u16>),
367    Binary(BinColumnView<'a>),
368    Date(&'a [Date]),
369    Time(&'a [Time]),
370    Timestamp(&'a [Timestamp]),
371    F64(&'a [f64]),
372    F32(&'a [f32]),
373    I8(&'a [i8]),
374    I16(&'a [i16]),
375    I32(&'a [i32]),
376    I64(&'a [i64]),
377    U8(&'a [u8]),
378    Bit(&'a [Bit]),
379    Numeric(&'a [Numeric]),
380    NullableDate(NullableSlice<'a, Date>),
381    NullableTime(NullableSlice<'a, Time>),
382    NullableTimestamp(NullableSlice<'a, Timestamp>),
383    NullableF64(NullableSlice<'a, f64>),
384    NullableF32(NullableSlice<'a, f32>),
385    NullableI8(NullableSlice<'a, i8>),
386    NullableI16(NullableSlice<'a, i16>),
387    NullableI32(NullableSlice<'a, i32>),
388    NullableI64(NullableSlice<'a, i64>),
389    NullableU8(NullableSlice<'a, u8>),
390    NullableBit(NullableSlice<'a, Bit>),
391    NullableNumeric(NullableSlice<'a, Numeric>),
392}
393
394impl<'a> AnySlice<'a> {
395    /// This method is useful if you expect the variant to be [`AnySlice::Text`]. It allows you to
396    /// unwrap the inner column view without explictly matching it.
397    pub fn as_text_view(self) -> Option<TextColumnView<'a, u8>> {
398        if let Self::Text(view) = self {
399            Some(view)
400        } else {
401            None
402        }
403    }
404
405    /// This method is useful if you expect the variant to be [`AnySlice::WText`]. It allows you to
406    /// unwrap the inner column view without explictly matching it.
407    pub fn as_w_text_view(self) -> Option<TextColumnView<'a, u16>> {
408        if let Self::WText(view) = self {
409            Some(view)
410        } else {
411            None
412        }
413    }
414
415    /// This method is useful if you expect the variant to be [`AnySlice::Binary`]. It allows you to
416    /// unwrap the inner column view without explictly matching it.
417    pub fn as_bin_view(self) -> Option<BinColumnView<'a>> {
418        if let Self::Binary(view) = self {
419            Some(view)
420        } else {
421            None
422        }
423    }
424
425    /// Extract the array type from an [`AnySlice`].
426    pub fn as_slice<I: Item>(self) -> Option<&'a [I]> {
427        I::as_slice(self)
428    }
429
430    /// Extract the typed nullable buffer from an [`AnySlice`].
431    pub fn as_nullable_slice<I: Item>(self) -> Option<NullableSlice<'a, I>> {
432        I::as_nullable_slice(self)
433    }
434}
435
436unsafe impl<'a> BoundInputSlice<'a> for AnyBuffer {
437    type SliceMut = AnySliceMut<'a>;
438
439    unsafe fn as_view_mut(
440        &'a mut self,
441        parameter_index: u16,
442        stmt: StatementRef<'a>,
443    ) -> Self::SliceMut {
444        let num_rows = self.capacity();
445        unsafe {
446            match self {
447                AnyBuffer::Binary(column) => {
448                    AnySliceMut::Binary(column.as_view_mut(parameter_index, stmt))
449                }
450                AnyBuffer::Text(column) => {
451                    AnySliceMut::Text(column.as_view_mut(parameter_index, stmt))
452                }
453                AnyBuffer::WText(column) => {
454                    AnySliceMut::WText(column.as_view_mut(parameter_index, stmt))
455                }
456                AnyBuffer::Date(column) => AnySliceMut::Date(column),
457                AnyBuffer::Time(column) => AnySliceMut::Time(column),
458                AnyBuffer::Timestamp(column) => AnySliceMut::Timestamp(column),
459                AnyBuffer::F64(column) => AnySliceMut::F64(column),
460                AnyBuffer::F32(column) => AnySliceMut::F32(column),
461                AnyBuffer::I8(column) => AnySliceMut::I8(column),
462                AnyBuffer::I16(column) => AnySliceMut::I16(column),
463                AnyBuffer::I32(column) => AnySliceMut::I32(column),
464                AnyBuffer::I64(column) => AnySliceMut::I64(column),
465                AnyBuffer::U8(column) => AnySliceMut::U8(column),
466                AnyBuffer::Bit(column) => AnySliceMut::Bit(column),
467                AnyBuffer::Numeric(column) => AnySliceMut::Numeric(&mut column.value),
468                AnyBuffer::NullableDate(column) => {
469                    AnySliceMut::NullableDate(column.writer_n(num_rows))
470                }
471                AnyBuffer::NullableTime(column) => {
472                    AnySliceMut::NullableTime(column.writer_n(num_rows))
473                }
474                AnyBuffer::NullableTimestamp(column) => {
475                    AnySliceMut::NullableTimestamp(column.writer_n(num_rows))
476                }
477                AnyBuffer::NullableF64(column) => {
478                    AnySliceMut::NullableF64(column.writer_n(num_rows))
479                }
480                AnyBuffer::NullableF32(column) => {
481                    AnySliceMut::NullableF32(column.writer_n(num_rows))
482                }
483                AnyBuffer::NullableI8(column) => AnySliceMut::NullableI8(column.writer_n(num_rows)),
484                AnyBuffer::NullableI16(column) => {
485                    AnySliceMut::NullableI16(column.writer_n(num_rows))
486                }
487                AnyBuffer::NullableI32(column) => {
488                    AnySliceMut::NullableI32(column.writer_n(num_rows))
489                }
490                AnyBuffer::NullableI64(column) => {
491                    AnySliceMut::NullableI64(column.writer_n(num_rows))
492                }
493                AnyBuffer::NullableU8(column) => AnySliceMut::NullableU8(column.writer_n(num_rows)),
494                AnyBuffer::NullableBit(column) => {
495                    AnySliceMut::NullableBit(column.writer_n(num_rows))
496                }
497            }
498        }
499    }
500}
501
502/// A mutable slice of an input buffer, with runtime type information. Edit values in this slice in
503/// order to send parameters in bulk to a database.
504pub enum AnySliceMut<'a> {
505    Text(TextColumnSliceMut<'a, u8>),
506    /// Nullable character data encoded in UTF-16.
507    WText(TextColumnSliceMut<'a, u16>),
508    Binary(BinColumnSliceMut<'a>),
509    Date(&'a mut [Date]),
510    Time(&'a mut [Time]),
511    Timestamp(&'a mut [Timestamp]),
512    F64(&'a mut [f64]),
513    F32(&'a mut [f32]),
514    I8(&'a mut [i8]),
515    I16(&'a mut [i16]),
516    I32(&'a mut [i32]),
517    I64(&'a mut [i64]),
518    U8(&'a mut [u8]),
519    Bit(&'a mut [Bit]),
520    Numeric(&'a mut [Numeric]),
521    NullableDate(NullableSliceMut<'a, Date>),
522    NullableTime(NullableSliceMut<'a, Time>),
523    NullableTimestamp(NullableSliceMut<'a, Timestamp>),
524    NullableF64(NullableSliceMut<'a, f64>),
525    NullableF32(NullableSliceMut<'a, f32>),
526    NullableI8(NullableSliceMut<'a, i8>),
527    NullableI16(NullableSliceMut<'a, i16>),
528    NullableI32(NullableSliceMut<'a, i32>),
529    NullableI64(NullableSliceMut<'a, i64>),
530    NullableU8(NullableSliceMut<'a, u8>),
531    NullableBit(NullableSliceMut<'a, Bit>),
532}
533
534impl<'a> AnySliceMut<'a> {
535    /// This method is useful if you expect the variant to be [`AnySliceMut::Binary`]. It allows you
536    /// to unwrap the inner column view without explictly matching it.
537    pub fn as_bin_view(self) -> Option<BinColumnSliceMut<'a>> {
538        if let Self::Binary(view) = self {
539            Some(view)
540        } else {
541            None
542        }
543    }
544
545    /// This method is useful if you expect the variant to be [`AnySliceMut::Text`]. It allows you
546    /// to unwrap the inner column view without explictly matching it.
547    pub fn as_text_view(self) -> Option<TextColumnSliceMut<'a, u8>> {
548        if let Self::Text(view) = self {
549            Some(view)
550        } else {
551            None
552        }
553    }
554
555    /// This method is useful if you expect the variant to be [`AnySliceMut::WText`]. It allows you
556    /// to unwrap the inner column view without explictly matching it.
557    pub fn as_w_text_view(self) -> Option<TextColumnSliceMut<'a, u16>> {
558        if let Self::WText(view) = self {
559            Some(view)
560        } else {
561            None
562        }
563    }
564
565    /// Extract the array type from an [`AnySliceMut`].
566    pub fn as_slice<I: Item>(self) -> Option<&'a mut [I]> {
567        I::as_slice_mut(self)
568    }
569
570    /// Extract the typed nullable buffer from an [`AnySliceMut`].
571    pub fn as_nullable_slice<I: Item>(self) -> Option<NullableSliceMut<'a, I>> {
572        I::as_nullable_slice_mut(self)
573    }
574}
575
576unsafe impl ColumnBuffer for AnyBuffer {
577    type View<'a> = AnySlice<'a>;
578
579    fn capacity(&self) -> usize {
580        match self {
581            AnyBuffer::Binary(col) => col.capacity(),
582            AnyBuffer::Text(col) => col.capacity(),
583            AnyBuffer::WText(col) => col.capacity(),
584            AnyBuffer::Date(col) => col.capacity(),
585            AnyBuffer::Time(col) => col.capacity(),
586            AnyBuffer::Timestamp(col) => col.capacity(),
587            AnyBuffer::F64(col) => col.capacity(),
588            AnyBuffer::F32(col) => col.capacity(),
589            AnyBuffer::I8(col) => col.capacity(),
590            AnyBuffer::I16(col) => col.capacity(),
591            AnyBuffer::I32(col) => col.capacity(),
592            AnyBuffer::I64(col) => col.capacity(),
593            AnyBuffer::U8(col) => col.capacity(),
594            AnyBuffer::Bit(col) => col.capacity(),
595            AnyBuffer::Numeric(col) => col.capacity(),
596            AnyBuffer::NullableDate(col) => col.capacity(),
597            AnyBuffer::NullableTime(col) => col.capacity(),
598            AnyBuffer::NullableTimestamp(col) => col.capacity(),
599            AnyBuffer::NullableF64(col) => col.capacity(),
600            AnyBuffer::NullableF32(col) => col.capacity(),
601            AnyBuffer::NullableI8(col) => col.capacity(),
602            AnyBuffer::NullableI16(col) => col.capacity(),
603            AnyBuffer::NullableI32(col) => col.capacity(),
604            AnyBuffer::NullableI64(col) => col.capacity(),
605            AnyBuffer::NullableU8(col) => col.capacity(),
606            AnyBuffer::NullableBit(col) => col.capacity(),
607        }
608    }
609
610    fn view(&self, valid_rows: usize) -> AnySlice<'_> {
611        match self {
612            AnyBuffer::Binary(col) => AnySlice::Binary(col.view(valid_rows)),
613            AnyBuffer::Text(col) => AnySlice::Text(col.view(valid_rows)),
614            AnyBuffer::WText(col) => AnySlice::WText(col.view(valid_rows)),
615            AnyBuffer::Date(col) => AnySlice::Date(&col[0..valid_rows]),
616            AnyBuffer::Time(col) => AnySlice::Time(&col[0..valid_rows]),
617            AnyBuffer::Timestamp(col) => AnySlice::Timestamp(&col[0..valid_rows]),
618            AnyBuffer::F64(col) => AnySlice::F64(&col[0..valid_rows]),
619            AnyBuffer::F32(col) => AnySlice::F32(&col[0..valid_rows]),
620            AnyBuffer::I8(col) => AnySlice::I8(&col[0..valid_rows]),
621            AnyBuffer::I16(col) => AnySlice::I16(&col[0..valid_rows]),
622            AnyBuffer::I32(col) => AnySlice::I32(&col[0..valid_rows]),
623            AnyBuffer::I64(col) => AnySlice::I64(&col[0..valid_rows]),
624            AnyBuffer::U8(col) => AnySlice::U8(&col[0..valid_rows]),
625            AnyBuffer::Bit(col) => AnySlice::Bit(&col[0..valid_rows]),
626            AnyBuffer::Numeric(col) => AnySlice::Numeric(&col.value[0..valid_rows]),
627            AnyBuffer::NullableDate(col) => AnySlice::NullableDate(col.iter(valid_rows)),
628            AnyBuffer::NullableTime(col) => AnySlice::NullableTime(col.iter(valid_rows)),
629            AnyBuffer::NullableTimestamp(col) => AnySlice::NullableTimestamp(col.iter(valid_rows)),
630            AnyBuffer::NullableF64(col) => AnySlice::NullableF64(col.iter(valid_rows)),
631            AnyBuffer::NullableF32(col) => AnySlice::NullableF32(col.iter(valid_rows)),
632            AnyBuffer::NullableI8(col) => AnySlice::NullableI8(col.iter(valid_rows)),
633            AnyBuffer::NullableI16(col) => AnySlice::NullableI16(col.iter(valid_rows)),
634            AnyBuffer::NullableI32(col) => AnySlice::NullableI32(col.iter(valid_rows)),
635            AnyBuffer::NullableI64(col) => AnySlice::NullableI64(col.iter(valid_rows)),
636            AnyBuffer::NullableU8(col) => AnySlice::NullableU8(col.iter(valid_rows)),
637            AnyBuffer::NullableBit(col) => AnySlice::NullableBit(col.iter(valid_rows)),
638        }
639    }
640
641    fn has_truncated_values(&self, num_rows: usize) -> Option<Indicator> {
642        match self {
643            AnyBuffer::Binary(col) => col.has_truncated_values(num_rows),
644            AnyBuffer::Text(col) => col.has_truncated_values(num_rows),
645            AnyBuffer::WText(col) => col.has_truncated_values(num_rows),
646            _ => None,
647        }
648    }
649}
650
651impl Resize for AnyBuffer {
652    fn resize(&mut self, new_capacity: usize) {
653        self.inner_mut().resize(new_capacity);
654    }
655}
656
657#[cfg(test)]
658mod tests {
659    use crate::buffers::{AnySlice, AnySliceMut, ColumnBuffer, Resize};
660
661    use super::AnyBuffer;
662
663    #[test]
664    fn any_buffer_is_resize() {
665        // Given an `AnyBuffer` with a capacity of 2 and values [1, 2]
666        let mut buffer = AnyBuffer::I32(vec![1, 2]);
667
668        // When we resize it to a capacity of 4
669        buffer.resize(4);
670
671        // Then the buffer should still have the same values in the first two positions and the
672        // remaining positions should be filled with default values (0 for i32)
673        assert_eq!(buffer.view(4).as_slice(), Some([1i32, 2, 0, 0].as_slice()));
674        // And the capacity should be 4
675        assert_eq!(buffer.capacity(), 4);
676    }
677
678    #[test]
679    fn slice_should_only_contain_part_of_the_buffer() {
680        let buffer = AnyBuffer::I32(vec![1, 2, 3]);
681
682        let view = buffer.view(2);
683
684        assert_eq!(Some([1, 2].as_slice()), view.as_slice::<i32>());
685    }
686
687    #[test]
688    fn slice_should_be_none_if_types_mismatch() {
689        let buffer = [1, 2, 3];
690        let view = AnySlice::I32(&buffer);
691        assert_eq!(None, view.as_slice::<i16>());
692    }
693
694    #[test]
695    fn slice_mut_should_be_none_if_types_mismatch() {
696        let mut buffer = [1, 2, 3];
697        let view = AnySliceMut::I32(&mut buffer);
698        assert_eq!(None, view.as_slice::<i16>());
699    }
700
701    #[test]
702    fn nullable_slice_should_be_none_if_buffer_is_non_nullable() {
703        let buffer = [1, 2, 3];
704        let view = AnySlice::I32(&buffer);
705        assert!(view.as_nullable_slice::<i32>().is_none());
706    }
707
708    #[test]
709    fn nullable_slice_mut_should_be_none_if_buffer_is_non_nullable() {
710        let mut buffer = [1, 2, 3];
711        let view = AnySliceMut::I32(&mut buffer);
712        assert!(view.as_nullable_slice::<i32>().is_none());
713    }
714}