use std::cmp::Ord;
use std::collections::*;
use std::fmt;
use std::hash::Hash;
use std::marker::PhantomData;
use serde::de::{DeserializeSeed, Deserializer, SeqAccess, Visitor};
use super::{Context, Trino, TrinoTy};
macro_rules! gen_seq {
($ty:ident, $insert:ident, $seed:ident) => {
gen_seq! { $ty<>, $insert, $seed }
};
($ty:ident < $($bound:ident ),* >, $insert:ident, $seed:ident) => {
impl<T: Trino + $($bound+)*> Trino for $ty<T> {
type ValueType<'a> = Vec<T::ValueType<'a>> where T: 'a;
type Seed<'a, 'de> = $seed<'a, T>;
fn value(&self) -> Self::ValueType<'_> {
self.iter().map(|t| t.value()).collect()
}
fn ty() -> TrinoTy {
TrinoTy::Array(Box::new(T::ty()))
}
fn seed<'a, 'de>(ctx: &'a Context) -> Self::Seed<'a, 'de> {
$seed::new(ctx)
}
fn empty() -> Self {
Default::default()
}
}
pub struct $seed<'a, T> {
ctx: &'a Context<'a>,
ty: &'a TrinoTy,
_marker: PhantomData<T>,
}
impl<'a, T> $seed<'a, T> {
pub(super) fn new(ctx: &'a Context) -> Self {
if let TrinoTy::Array(ty) = ctx.ty {
$seed {
ctx,
ty: &*ty,
_marker: PhantomData,
}
} else {
panic!("invalid context")
}
}
}
impl<'a, 'de, T: Trino + $($bound+)*> Visitor<'de> for $seed<'a, T> {
type Value = $ty<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("sequence of same trino type")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut ret: $ty<T> = Default::default();
let ctx = self.ctx.with_ty(self.ty);
while let Some(d) = seq.next_element_seed(T::seed(&ctx))? {
ret.$insert(d);
}
Ok(ret)
}
}
impl<'a, 'de, T: Trino + $($bound+)*> DeserializeSeed<'de> for $seed<'a, T> {
type Value = $ty<T>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(self)
}
}
};
}
gen_seq!(Vec, push, VecSeed);
gen_seq!(LinkedList, push_back, LinkedListSeed);
gen_seq!(VecDeque, push_back, VecDequeSeed);
gen_seq!(HashSet<Ord,Hash>, insert, HashSetSeed);
gen_seq!(BTreeSet<Ord>, insert, BTreeSetSeed);
gen_seq!(BinaryHeap<Ord>, push, BinaryHeapSeed);