use crate::{
buffers::Resize,
fixed_sized::{Bit, Pod},
handles::{CData, CDataMut},
};
use odbc_sys::{Date, NULL_DATA, Time, Timestamp};
use std::{
ffi::c_void,
mem::size_of,
ptr::{null, null_mut},
};
pub type OptF64Column = ColumnWithIndicator<f64>;
pub type OptF32Column = ColumnWithIndicator<f32>;
pub type OptDateColumn = ColumnWithIndicator<Date>;
pub type OptTimestampColumn = ColumnWithIndicator<Timestamp>;
pub type OptTimeColumn = ColumnWithIndicator<Time>;
pub type OptI8Column = ColumnWithIndicator<i8>;
pub type OptI16Column = ColumnWithIndicator<i16>;
pub type OptI32Column = ColumnWithIndicator<i32>;
pub type OptI64Column = ColumnWithIndicator<i64>;
pub type OptU8Column = ColumnWithIndicator<u8>;
pub type OptBitColumn = ColumnWithIndicator<Bit>;
#[derive(Debug)]
pub struct ColumnWithIndicator<T> {
values: Vec<T>,
indicators: Vec<isize>,
}
impl<T> ColumnWithIndicator<T>
where
T: Default + Clone,
{
pub fn new(batch_size: usize) -> Self {
Self {
values: vec![T::default(); batch_size],
indicators: vec![NULL_DATA; batch_size],
}
}
pub fn iter(&self, num_rows: usize) -> NullableSlice<'_, T> {
NullableSlice {
indicators: &self.indicators[0..num_rows],
values: &self.values[0..num_rows],
}
}
pub fn fill_null(&mut self, from: usize, to: usize) {
for index in from..to {
self.indicators[index] = NULL_DATA;
}
}
pub fn writer_n(&mut self, n: usize) -> NullableSliceMut<'_, T> {
NullableSliceMut {
indicators: &mut self.indicators[0..n],
values: &mut self.values[0..n],
}
}
pub fn capacity(&self) -> usize {
self.indicators.len()
}
}
#[derive(Debug, Clone, Copy)]
pub struct NullableSlice<'a, T> {
indicators: &'a [isize],
values: &'a [T],
}
impl<'a, T> NullableSlice<'a, T> {
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn raw_values(&self) -> (&'a [T], &'a [isize]) {
(self.values, self.indicators)
}
pub fn get(&self, index: usize) -> Option<&'a T> {
if self.indicators[index] == NULL_DATA {
None
} else {
Some(&self.values[index])
}
}
}
impl<'a, T> Iterator for NullableSlice<'a, T> {
type Item = Option<&'a T>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(&ind) = self.indicators.first() {
let item = if ind == NULL_DATA {
None
} else {
Some(&self.values[0])
};
self.indicators = &self.indicators[1..];
self.values = &self.values[1..];
Some(item)
} else {
None
}
}
}
unsafe impl<T> CData for ColumnWithIndicator<T>
where
T: Pod,
{
fn cdata_type(&self) -> odbc_sys::CDataType {
T::C_DATA_TYPE
}
fn indicator_ptr(&self) -> *const isize {
self.indicators.as_ptr()
}
fn value_ptr(&self) -> *const c_void {
self.values.as_ptr() as *const c_void
}
fn buffer_length(&self) -> isize {
size_of::<T>().try_into().unwrap()
}
}
unsafe impl<T> CDataMut for ColumnWithIndicator<T>
where
T: Pod,
{
fn mut_indicator_ptr(&mut self) -> *mut isize {
self.indicators.as_mut_ptr()
}
fn mut_value_ptr(&mut self) -> *mut c_void {
self.values.as_mut_ptr() as *mut c_void
}
}
unsafe impl<T> CData for Vec<T>
where
T: Pod,
{
fn cdata_type(&self) -> odbc_sys::CDataType {
T::C_DATA_TYPE
}
fn indicator_ptr(&self) -> *const isize {
null()
}
fn value_ptr(&self) -> *const c_void {
self.as_ptr() as *const c_void
}
fn buffer_length(&self) -> isize {
size_of::<T>().try_into().unwrap()
}
}
unsafe impl<T> CDataMut for Vec<T>
where
T: Pod,
{
fn mut_indicator_ptr(&mut self) -> *mut isize {
null_mut()
}
fn mut_value_ptr(&mut self) -> *mut c_void {
self.as_mut_ptr() as *mut c_void
}
}
#[derive(Debug)]
pub struct NullableSliceMut<'a, T> {
indicators: &'a mut [isize],
values: &'a mut [T],
}
impl<T> NullableSliceMut<'_, T> {
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn set_cell(&mut self, index: usize, cell: Option<T>) {
if let Some(value) = cell {
self.indicators[index] = 0;
self.values[index] = value;
} else {
self.indicators[index] = NULL_DATA;
}
}
pub fn raw_values(&mut self) -> (&mut [T], &mut [isize]) {
(self.values, self.indicators)
}
}
impl<T> NullableSliceMut<'_, T> {
pub fn write(&mut self, it: impl Iterator<Item = Option<T>>) {
for (index, item) in it.enumerate().take(self.values.len()) {
self.set_cell(index, item)
}
}
}
impl<T> Resize for ColumnWithIndicator<T>
where
T: Default + Clone,
{
fn resize(&mut self, new_size: usize) {
self.values.resize(new_size, T::default());
self.indicators.resize(new_size, NULL_DATA);
}
}
#[cfg(test)]
mod tests {
use crate::buffers::Resize;
use super::ColumnWithIndicator;
#[test]
fn column_with_indicator_is_resize() {
let mut column = ColumnWithIndicator::<i32>::new(2);
let mut writer = column.writer_n(2);
writer.set_cell(0, Some(1));
writer.set_cell(1, Some(2));
column.resize(3);
let reader = column.iter(3);
assert_eq!(reader.get(0), Some(&1));
assert_eq!(reader.get(1), Some(&2));
assert_eq!(reader.get(2), None);
}
}