cgp-serde 0.2.0

CGP-enabled serde implementation
Documentation
use cgp::prelude::*;
use serde::de::{DeserializeSeed, Visitor};

use crate::components::{CanDeserializeValue, ValueDeserializer, ValueDeserializerComponent};

pub struct DeserializeExtend;

#[cgp_impl(DeserializeExtend)]
#[uses(CanDeserializeValue<'de, Item>)]
impl<'de, Value, Item> ValueDeserializer<'de, Value>
where
    Value: Default + IntoIterator<Item = Item> + Extend<Item>,
{
    fn deserialize<D>(&self, deserializer: D) -> Result<Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_seq(DeserializeExtendVisitor {
            context: self,
            phantom: PhantomData,
        })
    }
}

struct DeserializeExtendVisitor<'a, Context, Value, Item> {
    context: &'a Context,
    phantom: PhantomData<(Value, Item)>,
}

impl<'de, 'a, Context, Value, Item> Visitor<'de>
    for DeserializeExtendVisitor<'a, Context, Value, Item>
where
    Value: Default + Extend<Item>,
    Context: CanDeserializeValue<'de, Item>,
{
    type Value = Value;

    fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
        write!(formatter, "sequence")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
    where
        A: serde::de::SeqAccess<'de>,
    {
        let mut value = Value::default();

        while let Some(item) = seq.next_element_seed(DeserializeExtendSeed {
            context: self.context,
            phantom: PhantomData,
        })? {
            value.extend(core::iter::once(item));
        }

        Ok(value)
    }
}

struct DeserializeExtendSeed<'a, Context, Item> {
    context: &'a Context,
    phantom: PhantomData<Item>,
}

impl<'de, 'a, Context, Item> DeserializeSeed<'de> for DeserializeExtendSeed<'a, Context, Item>
where
    Context: CanDeserializeValue<'de, Item>,
{
    type Value = Item;

    fn deserialize<D>(self, deserializer: D) -> Result<Item, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        self.context.deserialize(deserializer)
    }
}