uninode 0.4.2

Universal object type
Documentation
//
// Copyright (c) 2022 Oleg Lelenkov <o.lelenkov@gmail.com>
// Distributed under terms of the BSD 3-Clause license.
//

mod mapkey;
mod reference;
mod value;

use serde::de;
use std::{fmt, result};

use crate::value::{UniNode, Object, Array};

struct UniNodeVisitor;

type VResult<E> = result::Result<UniNode, E>;

impl<'de> de::Visitor<'de> for UniNodeVisitor {
    type Value = UniNode;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("any valid UniNode value")
    }

    fn visit_bool<E>(self, v: bool) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_i8<E>(self, v: i8) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_i16<E>(self, v: i16) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_i32<E>(self, v: i32) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_i64<E>(self, v: i64) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_u8<E>(self, v: u8) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_u16<E>(self, v: u16) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_u32<E>(self, v: u32) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_u64<E>(self, v: u64) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_f32<E>(self, v: f32) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_f64<E>(self, v: f64) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_str<E>(self, v: &str) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_string<E>(self, v: String) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_none<E>(self) -> VResult<E> {
        Ok(UniNode::Null)
    }

    fn visit_unit<E>(self) -> VResult<E> {
        Ok(UniNode::Null)
    }

    fn visit_bytes<E>(self, v: &[u8]) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_byte_buf<E>(self, v: Vec<u8>) -> VResult<E> {
        Ok(UniNode::from(v))
    }

    fn visit_some<D>(self, deserializer: D) -> VResult<D::Error>
    where
        D: de::Deserializer<'de>,
    {
        deserializer.deserialize_any(self)
    }

    fn visit_seq<A>(self, mut seq: A) -> VResult<A::Error>
    where
        A: de::SeqAccess<'de>,
    {
        let mut vec = Array::with_capacity(seq.size_hint().unwrap_or(0));
        while let Some(el) = seq.next_element()? {
            vec.push(el);
        }
        Ok(UniNode::Array(vec))
    }

    fn visit_map<A>(self, mut map: A) -> VResult<A::Error>
    where
        A: de::MapAccess<'de>,
    {
        let mut obj = Object::with_capacity(map.size_hint().unwrap_or(0));
        while let Some((key, val)) = map.next_entry()? {
            obj.insert(key, val);
        }
        Ok(UniNode::Object(obj))
    }
}

impl<'de> de::Deserialize<'de> for UniNode {
    fn deserialize<D>(deserializer: D) -> result::Result<UniNode, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        deserializer.deserialize_any(UniNodeVisitor)
    }
}

#[cfg(test)]
mod tests {
    use serde::de::Visitor;
    use serde::de::value;
    use serde::Deserialize;
    use crate::{unode, UniNode};
    use super::*;
    use std::fmt;
    use serde_bytes::ByteBuf;
    use crate::serialize::error::UniNodeSerError;

    #[test]
    fn visit_value() {
        let visitor = UniNodeVisitor;
        assert_eq!(
            visitor.visit_u8::<value::Error>(42).unwrap(),
            unode!(42u32)
        );
    }

    #[test]
    fn visit_bytes() {
        let bytes = UniNode::Bytes(vec![1, 2, 3]);
        assert_eq!(
            UniNodeVisitor
                .visit_bytes::<value::Error>(&[1, 2, 3])
                .unwrap(),
            bytes
        );
        assert_eq!(
            UniNodeVisitor
                .visit_byte_buf::<value::Error>(vec![1, 2, 3])
                .unwrap(),
            bytes
        );
    }

    #[test]
    fn visit_seq() {
        type SeqDe =
            value::SeqDeserializer<std::vec::IntoIter<u8>, value::Error>;
        let seq = SeqDe::new(vec![1, 2, 3].into_iter());
        assert_eq!(
            UniNodeVisitor.visit_seq(seq).unwrap(),
            unode!(1u8, 2u8, 3u8)
        );
    }

    #[test]
    fn visit_map() {
        type MapDe<'de> = value::MapDeserializer<
            'de,
            std::vec::IntoIter<(&'de str, u8)>,
            value::Error,
        >;
        let map =
            MapDe::new(vec![("one", 1), ("two", 2), ("three", 3)].into_iter());
        assert_eq!(
            UniNodeVisitor.visit_map(map).unwrap(),
            unode!("one" => 1u8, "two" => 2u8, "three" => 3u8)
        );
    }

    pub fn assert_deserialize<T>(node: UniNode, val: T)
    where
        T: de::DeserializeOwned + fmt::Debug + PartialEq,
    {
        assert_eq!(T::deserialize(&node).unwrap(), val);
        assert_eq!(T::deserialize(node).unwrap(), val);
    }

    #[test]
    fn deserialize_primitive() {
        assert_deserialize(unode!(4u8), 4u8);
        assert_deserialize(unode!(4u16), 4u16);
        assert_deserialize(unode!(4u32), 4u32);
        assert_deserialize(unode!(4u64), 4u64);
        assert_deserialize(unode!(4i8), 4i8);
        assert_deserialize(unode!(4i16), 4i16);
        assert_deserialize(unode!(4i32), 4i32);
        assert_deserialize(unode!(4i64), 4i64);
        assert_deserialize(unode!(4.2f32), 4.2f32);
        assert_deserialize(unode!(4.2f64), 4.2f64);
        assert_deserialize(unode!(true), true);
        assert_deserialize(unode!("a"), 'a');
        assert_deserialize(unode!("hello"), "hello".to_string());
        let bytes = ByteBuf::from(vec![1u8, 2u8]);
        assert_deserialize::<ByteBuf>(unode!(vec![1u8, 2u8]), bytes);
        let bytes = ByteBuf::from(vec![104, 101, 108, 108, 111]);
        assert_deserialize::<ByteBuf>(unode!("hello"), bytes);
        let bytes = ByteBuf::from(vec![1u8, 2u8, 3u8]);
        assert_deserialize::<ByteBuf>(unode!(1, 2, 3), bytes);

        assert_deserialize(unode!(42), Some(42));
        assert_deserialize::<Option<u32>>(unode!(), None);
        assert_deserialize::<()>(unode!(), ());
        assert_deserialize::<std::marker::PhantomData<u8>>(
            unode!(),
            std::marker::PhantomData,
        );
    }

    #[test]
    fn deserialize_seq() {
        let array = UniNode::Bytes(vec![1, 2, 3]);
        assert_eq!(Vec::<u32>::deserialize(&array).unwrap(), vec![1, 2, 3]);
        assert_eq!(Vec::<u32>::deserialize(array).unwrap(), vec![1, 2, 3]);

        let array = unode!(2u32, 3, 4);
        assert_eq!(Vec::<u32>::deserialize(&array).unwrap(), vec![2, 3, 4]);
        assert_eq!(Vec::<u32>::deserialize(array).unwrap(), vec![2, 3, 4]);

        let value = unode!(42u32);
        assert_eq!(Vec::<u32>::deserialize(&value).unwrap(), vec![42]);
        assert_eq!(Vec::<u32>::deserialize(value).unwrap(), vec![42]);

        let array = UniNode::Array(vec![]);
        assert_eq!(Vec::<f64>::deserialize(&array).unwrap(), vec![]);
        assert_eq!(Vec::<f64>::deserialize(array).unwrap(), vec![]);
    }

    #[test]
    fn deserialize_tuple() {
        let tup = ("one".to_string(), 1, 3.18);
        assert_deserialize(unode!("one", 1, 3.18), tup);
    }

    #[test]
    fn deserialize_tuple_struct() {
        #[derive(Deserialize, PartialEq, Debug)]
        struct Rgb(u8, u8, u8);

        let tup = Rgb(2, 3, 4);
        assert_deserialize(unode!(2u8, 3u8, 4u8), tup);
    }

    #[test]
    fn deserialize_newtype_struct() {
        #[derive(Debug, Deserialize, PartialEq)]
        struct NewTypeStruct(u8);
        assert_deserialize(unode!(2u8), NewTypeStruct(2));

        #[derive(Debug, Deserialize, PartialEq)]
        enum NewTypeEnum {
            V(u8),
        }
        assert_deserialize(unode!("V" => 4u8), NewTypeEnum::V(4));
    }

    #[test]
    fn deserialize_map() {
        #[derive(PartialEq, Eq, Hash, Deserialize, Debug)]
        struct Key(u8);
        let mut map = std::collections::HashMap::new();
        map.insert(Key(1), "One".to_string());
        map.insert(Key(2), "Two".to_string());
        map.insert(Key(3), "Three".to_string());

        assert_deserialize(
            unode! {"1" => "One", "2" => "Two", "3" => "Three"},
            map,
        );
    }

    #[test]
    fn deserialize_struct_test() {
        #[derive(Debug, Deserialize, PartialEq)]
        struct Point {
            x: i32,
            y: i32,
        }

        impl Point {
            fn new(x: i32, y: i32) -> Self {
                Self { x, y }
            }
        }

        match Point::deserialize(unode!(1i8)).unwrap_err() {
            UniNodeSerError::Custom(msg) => assert_eq!(
                msg,
                String::from(
                    "invalid type: integer `1`, expected struct Point"
                )
            ),
            _ => panic!("Unknown error"),
        }

        #[derive(Debug, Deserialize, PartialEq)]
        struct Test {
            int: u32,
            float: f64,
            text: String,
            data: Vec<Point>,
            node: UniNode,
            bytes: Vec<u8>,
            points: Vec<Point>,
        }

        let data = Test {
            int: 42,
            float: 3.18,
            text: "hello".to_string(),
            data: vec![Point::new(1, 2), Point::new(2, 3), Point::new(3, 4)],
            node: 10.into(),
            bytes: vec![97, 98, 99],
            points: vec![Point::new(4, 6)],
        };

        let node = unode! {
            "int" => 42u32,
            "float" => 3.18,
            "text" => "hello",
            "data" => unode![
                unode!{"x" => 1, "y" => 2},
                unode!{"x" => 2, "y" => 3},
                unode!{"x" => 3, "y" => 4},
            ],
            "node" => 10,
            "bytes" => vec![97u8, 98u8, 99u8],
            "points" => unode!{"x" => 4, "y" => 6},
        };

        assert_deserialize(node, data);
    }

    #[test]
    fn deserialize_enum() {
        use std::ops::Bound;
        assert_deserialize(unode!("Unbounded"), Bound::<usize>::Unbounded);
    }

    #[test]
    fn deserialize_tuple_variant() {
        #[derive(Deserialize, Debug, PartialEq)]
        enum E {
            T(u8, u8),
            U(String, u32, u32),
        }
        let tup = E::T(2, 3);
        assert_deserialize(unode!("T" => unode![2u8, 3u8]), tup);
    }

    #[test]
    fn deserialize_struct_variant() {
        #[derive(Deserialize, PartialEq, Debug)]
        enum E {
            S { r: u8, g: u8, b: u8 },
        }
        let data = E::S { r: 3, g: 5, b: 6 };
        let node = unode! {
            "S" => unode!{"r" => 3u8, "g" => 5u8, "b" => 6u8}
        };
        assert_deserialize(node, data);
    }
}