use super::{
BinColumn, BinColumnSlice, BufferDesc, ColumnBuffer, ColumnarBuffer, Indicator, NullableSlice,
Slice, TextColumn, TextColumnSlice, column_with_indicator::ColumnWithIndicator,
};
use crate::{
Error,
fixed_sized::Pod,
handles::{CData, CDataMut},
};
use std::{any::Any, collections::HashSet, ffi::c_void};
pub type ColumnarDynBuffer = ColumnarBuffer<BoxColumnBuffer>;
impl ColumnarDynBuffer {
pub fn from_descs(capacity: usize, descs: impl IntoIterator<Item = BufferDesc>) -> Self {
let mut column_index = 0;
let columns = descs
.into_iter()
.map(move |desc| {
let buffer = desc.column_buffer(capacity);
column_index += 1;
(column_index, buffer)
})
.collect();
unsafe { ColumnarBuffer::new_unchecked(capacity, columns) }
}
pub fn try_from_descs(
capacity: usize,
descs: impl IntoIterator<Item = BufferDesc>,
) -> Result<Self, Error> {
let mut column_index = 0;
let columns = descs
.into_iter()
.map(move |desc| {
let buffer = desc
.try_column_buffer(capacity)
.map_err(|source| source.add_context(column_index))?;
column_index += 1;
Ok::<_, Error>((column_index, buffer))
})
.collect::<Result<_, _>>()?;
Ok(unsafe { ColumnarBuffer::new_unchecked(capacity, columns) })
}
pub fn from_descs_and_indices(
max_rows: usize,
description: impl Iterator<Item = (u16, BufferDesc)>,
) -> Self {
let columns: Vec<_> = description
.map(|(col_index, buffer_desc)| (col_index, buffer_desc.column_buffer(max_rows)))
.collect();
let mut indices = HashSet::new();
if columns
.iter()
.any(move |&(col_index, _)| !indices.insert(col_index))
{
panic!("Column indices must be unique.")
}
ColumnarBuffer::new(columns)
}
}
pub type BoxColumnBuffer = Box<dyn AnyColumnBuffer>;
pub trait AnyColumnBuffer: ColumnBuffer + Any + Send {}
impl<T> AnyColumnBuffer for T where T: ColumnBuffer + Any + Send {}
unsafe impl CData for Box<dyn AnyColumnBuffer> {
fn cdata_type(&self) -> odbc_sys::CDataType {
self.as_ref().cdata_type()
}
fn indicator_ptr(&self) -> *const isize {
self.as_ref().indicator_ptr()
}
fn value_ptr(&self) -> *const c_void {
self.as_ref().value_ptr()
}
fn buffer_length(&self) -> isize {
self.as_ref().buffer_length()
}
}
unsafe impl CDataMut for Box<dyn AnyColumnBuffer> {
fn mut_indicator_ptr(&mut self) -> *mut isize {
self.as_mut().mut_indicator_ptr()
}
fn mut_value_ptr(&mut self) -> *mut c_void {
self.as_mut().mut_value_ptr()
}
}
unsafe impl ColumnBuffer for Box<dyn AnyColumnBuffer> {
fn capacity(&self) -> usize {
self.as_ref().capacity()
}
fn has_truncated_values(&self, num_rows: usize) -> Option<Indicator> {
self.as_ref().has_truncated_values(num_rows)
}
}
unsafe impl Slice for Box<dyn AnyColumnBuffer> {
type Slice<'a> = AnyColumnBufferSlice<'a>;
fn slice(&self, valid_rows: usize) -> AnyColumnBufferSlice<'_> {
AnyColumnBufferSlice {
buffer: self,
valid_rows,
}
}
}
#[derive(Clone, Copy)]
pub struct AnyColumnBufferSlice<'a> {
buffer: &'a BoxColumnBuffer,
valid_rows: usize,
}
impl<'a> AnyColumnBufferSlice<'a> {
pub fn of<T>(self) -> Option<T::Slice<'a>>
where
T: Slice + 'static,
{
let buffer: &dyn Any = self.buffer.as_ref();
let buffer = buffer.downcast_ref::<T>()?;
Some(T::slice(buffer, self.valid_rows))
}
pub fn as_text(self) -> Option<TextColumnSlice<'a, u8>> {
self.of::<TextColumn<u8>>()
}
pub fn as_wide_text(self) -> Option<TextColumnSlice<'a, u16>> {
self.of::<TextColumn<u16>>()
}
pub fn as_binary(self) -> Option<BinColumnSlice<'a>> {
self.of::<BinColumn>()
}
pub fn as_slice<T>(self) -> Option<&'a [T]>
where
T: Pod,
{
self.of::<Vec<T>>()
}
pub fn as_nullable_slice<T>(self) -> Option<NullableSlice<'a, T>>
where
T: Pod,
{
self.of::<ColumnWithIndicator<T>>()
}
}
#[cfg(test)]
mod tests {
use super::{BufferDesc, ColumnarDynBuffer};
#[test]
#[should_panic(expected = "Column indices must be unique.")]
fn assert_unique_column_indices() {
let bd = BufferDesc::I32 { nullable: false };
ColumnarDynBuffer::from_descs_and_indices(1, [(1, bd), (2, bd), (1, bd)].iter().cloned());
}
}