use std::{mem, ops::Deref};
use crate::{
Error, RowSetBuffer, TruncationInfo,
buffers::Indicator,
handles::{CDataMut, Statement, StatementRef},
};
pub unsafe trait FetchRow: Copy {
unsafe fn bind_columns_to_cursor(&mut self, cursor: StatementRef<'_>) -> Result<(), Error>;
fn find_truncation(&self) -> Option<TruncationInfo>;
}
pub struct RowVec<R> {
num_rows: Box<usize>,
rows: Vec<R>,
}
impl<R> RowVec<R> {
pub fn new(capacity: usize) -> Self
where
R: Default + Clone + Copy,
{
if capacity == 0 {
panic!("RowWiseBuffer must have a capacity of at least `1`.")
}
RowVec {
num_rows: Box::new(0),
rows: vec![R::default(); capacity],
}
}
pub fn num_rows(&self) -> usize {
*self.num_rows
}
}
impl<R> Deref for RowVec<R> {
type Target = [R];
fn deref(&self) -> &[R] {
&self.rows[..*self.num_rows]
}
}
unsafe impl<R> RowSetBuffer for RowVec<R>
where
R: FetchRow,
{
fn bind_type(&self) -> usize {
mem::size_of::<R>()
}
fn row_array_size(&self) -> usize {
self.rows.len()
}
fn mut_num_fetch_rows(&mut self) -> &mut usize {
&mut self.num_rows
}
unsafe fn bind_colmuns_to_cursor(&mut self, cursor: StatementRef<'_>) -> Result<(), Error> {
let first = self
.rows
.first_mut()
.expect("rows in Row Wise buffers must not be empty.");
unsafe { first.bind_columns_to_cursor(cursor) }
}
fn find_truncation(&self) -> Option<TruncationInfo> {
self.rows
.iter()
.take(*self.num_rows)
.find_map(|row| row.find_truncation())
}
}
pub unsafe trait FetchRowMember: CDataMut + Copy {
fn find_truncation(&self, buffer_index: usize) -> Option<TruncationInfo> {
self.indicator().map(|indicator| TruncationInfo {
indicator: indicator.length(),
buffer_index,
})
}
fn indicator(&self) -> Option<Indicator>;
unsafe fn bind_to_col(
&mut self,
col_index: u16,
cursor: &mut StatementRef<'_>,
) -> Result<(), Error> {
unsafe { cursor.bind_col(col_index, self).into_result(cursor) }
}
}
macro_rules! impl_bind_columns_to_cursor {
($offset:expr, $cursor:ident,) => (
Ok(())
);
($offset:expr, $cursor:ident, $head:ident, $($tail:ident,)*) => (
{
$head.bind_to_col($offset, &mut $cursor)?;
impl_bind_columns_to_cursor!($offset+1, $cursor, $($tail,)*)
}
);
}
macro_rules! impl_find_truncation {
($offset:expr,) => (
None
);
($offset:expr, $head:ident, $($tail:ident,)*) => (
{
if let Some(truncation_info) = $head.find_truncation($offset) {
return Some(truncation_info);
}
impl_find_truncation!($offset+1, $($tail,)*)
}
);
}
macro_rules! impl_fetch_row_for_tuple{
($($t:ident)*) => (
#[allow(unused_mut)]
#[allow(unused_variables)]
#[allow(non_snake_case)]
unsafe impl<$($t:FetchRowMember,)*> FetchRow for ($($t,)*)
{
unsafe fn bind_columns_to_cursor(&mut self, mut cursor: StatementRef<'_>) -> Result<(), Error> {
let &mut ($(ref mut $t,)*) = self;
#[allow(unused_unsafe)] unsafe {
impl_bind_columns_to_cursor!(1, cursor, $($t,)*)
}
}
fn find_truncation(&self) -> Option<TruncationInfo> {
let &($(ref $t,)*) = self;
impl_find_truncation!(0, $($t,)*)
}
}
);
}
impl_fetch_row_for_tuple! {}
impl_fetch_row_for_tuple! { A }
impl_fetch_row_for_tuple! { A B }
impl_fetch_row_for_tuple! { A B C }
impl_fetch_row_for_tuple! { A B C D }
impl_fetch_row_for_tuple! { A B C D E }
impl_fetch_row_for_tuple! { A B C D E F }
impl_fetch_row_for_tuple! { A B C D E F G }
impl_fetch_row_for_tuple! { A B C D E F G H }
impl_fetch_row_for_tuple! { A B C D E F G H I }
impl_fetch_row_for_tuple! { A B C D E F G H I J }
impl_fetch_row_for_tuple! { A B C D E F G H I J K }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R S }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R S T }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R S T U }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R S T U V }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R S T U V W }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R S T U V W X }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R S T U V W X Y }
impl_fetch_row_for_tuple! { A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}
#[cfg(test)]
mod tests {
use super::RowVec;
#[derive(Default, Clone, Copy)]
struct DummyRow;
#[test]
#[should_panic]
fn construction_should_panic_on_capacity_zero() {
RowVec::<DummyRow>::new(0);
}
#[test]
#[should_panic]
fn index_should_panic_on_out_of_bound_access() {
let buffer = RowVec::<DummyRow>::new(1);
let _ = buffer[0];
}
}