smallish 0.1.0

Lightweight, no-std syntax for configuration and scripting.
Documentation
use as_variant::as_variant;
use serde::de;

use crate::de::deserialize::{forward_to_inner_deserialize, Error, SmallishDe};
use crate::syntax::{Event, Value};

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) struct EscapedHandler<'a, De> {
    de: &'a mut De,
}

impl<'a, De> EscapedHandler<'a, De> {
    pub(crate) fn new(de: &'a mut De) -> Self {
        Self { de }
    }
}

impl<'a, 'de, De> SmallishDe<'de> for &mut EscapedHandler<'a, De>
where
    for<'b> &'b mut De: SmallishDe<'de>,
{
    #[inline]
    fn base(self) -> impl SmallishDe<'de> {
        self.de.base()
    }
}

impl<'a, 'de, De> de::Deserializer<'de> for &mut EscapedHandler<'a, De>
where
    for<'b> &'b mut De: SmallishDe<'de>,
{
    type Error = Error;

    forward_to_inner_deserialize! {
        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char
        option unit unit_struct seq tuple
        tuple_struct map enum identifier ignored_any
    }

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.de.peek()? {
            Event::Value(Value::Str(_)) => self.deserialize_str(visitor),
            Event::Value(Value::Bytes(_)) => self.deserialize_bytes(visitor),
            _ => self.de.deserialize_any(visitor),
        }
    }

    fn deserialize_newtype_struct<V>(
        self,
        name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.hook_special(name, visitor, |de, visitor| {
            visitor.visit_newtype_struct(de)
        })
    }

    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let v = self
            .de
            .next_with(as_variant!(Event::Value(Value::Str(v)) => v))?;
        visitor.visit_borrowed_str(*v)
    }

    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_str(visitor)
    }

    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let v = self
            .de
            .next_with(as_variant!(Event::Value(Value::Bytes(v)) => v))?;
        visitor.visit_borrowed_bytes(*v)
    }

    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_bytes(visitor)
    }

    fn deserialize_struct<V>(
        self,
        name: &'static str,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.hook_special(name, visitor, |de, visitor| de.deserialize_map(visitor))
    }
}

#[cfg(test)]
mod test {
    extern crate alloc;

    #[test]
    fn val_str() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<&str> = from_slice_escaped(Flavor::Value, br#" "\n" "#, &mut []).unwrap();
        assert_eq!("\\n", *v);
    }
    #[test]
    fn val_string() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<alloc::string::String> =
            from_slice_escaped(Flavor::Value, br#" "\n" "#, &mut []).unwrap();
        assert_eq!("\\n", *v);
    }

    #[test]
    fn val_bytes() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<&[u8]> = from_slice_escaped(Flavor::Value, br#" b"\n" "#, &mut []).unwrap();
        assert_eq!(b"\\n".as_ref(), *v);
    }
    #[test]
    fn val_byte_buf() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<serde_bytes::ByteBuf> =
            from_slice_escaped(Flavor::Value, br#" b"\n" "#, &mut []).unwrap();
        assert_eq!(b"\\n".as_ref(), v.to_vec());
    }

    #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
    struct Newtype<T>(T);
    #[test]
    fn newtype_str() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<Newtype<&str>> =
            from_slice_escaped(Flavor::Value, br#" "\n" "#, &mut []).unwrap();
        let v = v.0;
        assert_eq!("\\n", v);
    }
    #[test]
    fn newtype_bytes() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<Newtype<&[u8]>> =
            from_slice_escaped(Flavor::Value, br#" b"\n" "#, &mut []).unwrap();
        let v = v.0;
        assert_eq!(b"\\n".as_ref(), v);
    }

    #[test]
    fn escaped_located_str() {
        use crate::{
            from_slice_escaped,
            types::{Escaped, Located},
            Flavor,
        };
        let v: Escaped<Located<&str>> =
            from_slice_escaped(Flavor::Value, br#" "\n" "#, &mut []).unwrap();
        assert_eq!("\\n", **v);
    }
    #[test]
    fn escaped_located_bytes() {
        use crate::{
            from_slice_escaped,
            types::{Escaped, Located},
            Flavor,
        };
        let v: Escaped<Located<&[u8]>> =
            from_slice_escaped(Flavor::Value, br#" b"\n" "#, &mut []).unwrap();
        assert_eq!(b"\\n".as_ref(), **v);
    }

    #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
    enum Enum<T> {
        Variant(crate::types::Escaped<T>),
    }
    #[test]
    fn enum_escaped_str() {
        use crate::{from_slice_escaped, Flavor};
        let v: Enum<&str> =
            from_slice_escaped(Flavor::Value, br#" Variant "\n" "#, &mut []).unwrap();
        let Enum::Variant(s) = v;
        assert_eq!("\\n", *s);
    }
    #[test]
    fn enum_escaped_bytes() {
        use crate::{from_slice_escaped, Flavor};
        let v: Enum<&[u8]> =
            from_slice_escaped(Flavor::Value, br#" Variant b"\n" "#, &mut []).unwrap();
        let Enum::Variant(s) = v;
        assert_eq!(b"\\n", *s);
    }

    #[derive(Debug, PartialEq, serde::Deserialize)]
    #[serde(untagged)]
    enum AnyEnum<'a> {
        Unit(()),
        String(&'a str),
        Bytes(&'a [u8]),
    }
    #[test]
    fn escaped_any_unit() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<AnyEnum> = from_slice_escaped(Flavor::Value, br#" () "#, &mut []).unwrap();
        assert_eq!(*v, AnyEnum::Unit(()));
    }
    #[test]
    fn escaped_any_str() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<AnyEnum> =
            from_slice_escaped(Flavor::Value, b" \"a\\n\" ", &mut []).unwrap();
        assert_eq!(*v, AnyEnum::String("a\\n"));
    }
    #[test]
    fn escaped_any_bytes() {
        use crate::{from_slice_escaped, types::Escaped, Flavor};
        let v: Escaped<AnyEnum> =
            from_slice_escaped(Flavor::Value, b" b\"a\xf0\" ", &mut []).unwrap();
        assert_eq!(*v, AnyEnum::Bytes(b"a\xf0"));
    }
}