use std::{marker::PhantomData, rc::Rc, sync::Arc};
use sqlx_core::{
database::Database,
encode::{Encode, IsNull},
error::BoxDynError,
types::Type,
};
use crate::{arguments::ExaBuffer, Exasol};
pub trait ExaHasArrayType: Type<Exasol> {}
impl<T> ExaHasArrayType for &T where T: ExaHasArrayType {}
#[derive(Debug)]
#[repr(transparent)]
pub struct ExaIter<I, T> {
into_iter: I,
_marker: PhantomData<fn() -> T>,
}
impl<I, T> ExaIter<I, T>
where
I: IntoIterator<Item = T> + Clone,
T: for<'q> Encode<'q, Exasol> + ExaHasArrayType + Copy,
{
pub fn new(into_iter: I) -> Self {
Self {
into_iter,
_marker: PhantomData,
}
}
}
impl<I, T> Type<Exasol> for ExaIter<I, T>
where
I: IntoIterator<Item = T> + Clone,
T: ExaHasArrayType + Copy,
{
fn type_info() -> <Exasol as Database>::TypeInfo {
T::type_info()
}
}
impl<I, T> Encode<'_, Exasol> for ExaIter<I, T>
where
I: IntoIterator<Item = T> + Clone,
T: for<'q> Encode<'q, Exasol> + Copy,
{
fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
buf.append_iter(self.into_iter.clone())?;
Ok(IsNull::No)
}
fn size_hint(&self) -> usize {
2 + self
.into_iter
.clone()
.into_iter()
.fold(0, |sum, item| sum + item.size_hint())
}
}
macro_rules! forward_arr_type_impl {
($for_type:ty, $($generics:tt)*) => {
impl<T, $($generics)*> Type<Exasol> for $for_type
where
T: ExaHasArrayType,
{
fn type_info() -> <Exasol as Database>::TypeInfo {
T::type_info()
}
}
};
($for_type:ty) => {
forward_arr_type_impl!($for_type,);
}
}
macro_rules! forward_arr_encode_impl {
($for_type:ty, $($generics:tt)*) => {
impl<T, $($generics)*> Encode<'_, Exasol> for $for_type
where
for<'q> T: Encode<'q, Exasol> + ExaHasArrayType,
{
fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
ExaIter::new(AsRef::<[T]>::as_ref(&self)).encode_by_ref(buf)
}
fn size_hint(&self) -> usize {
ExaIter::new(AsRef::<[T]>::as_ref(&self)).size_hint()
}
}
};
($for_type:ty) => {
forward_arr_encode_impl!($for_type,);
}
}
forward_arr_type_impl!([T]);
forward_arr_type_impl!([T; N], const N: usize);
forward_arr_type_impl!(Vec<T>);
forward_arr_encode_impl!(&[T]);
forward_arr_encode_impl!([T; N], const N: usize);
forward_arr_encode_impl!(Vec<T>);
forward_arr_encode_impl!(Box<[T]>);
forward_arr_encode_impl!(Rc<[T]>);
forward_arr_encode_impl!(Arc<[T]>);