rocstr 0.6.2

An immutable fixed capacity stack based generic copy string
Documentation
//! Serde Serialize and Deserialize implementation

use serde::Deserialize;
use serde::Serialize;

use crate::rocstr::RocStr;

struct RocStrVisitor<const SIZE: usize>;

impl<const SIZE: usize> Serialize for RocStr<SIZE> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.as_str().serialize(serializer)
    }
}

impl<'de, const SIZE: usize> Deserialize<'de> for RocStr<SIZE> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_any(RocStrVisitor::<SIZE>)
    }
}

#[cfg(not(feature = "std"))]
mod no_std_rocstr {
    use core::fmt;

    use serde::de::Visitor;

    impl<'de, const SIZE: usize> Visitor<'de> for RocStrVisitor<SIZE> {
        type Value = RocStr<SIZE>;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a valid utf-8 string")
        }

        fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            match v {
                true => Ok(RocStr::<SIZE>::from("true")),
                false => Ok(RocStr::<SIZE>::from("false")),
            }
        }

        fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v).reshape::<SIZE>())
        }

        fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v).reshape::<SIZE>())
        }

        fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v).reshape::<SIZE>())
        }

        fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v).reshape::<SIZE>())
        }

        fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            let mut buffer = [0; 4];
            let encoded = v.encode_utf8(&mut buffer);
            Ok(RocStr::from(encoded as &str))
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v))
        }

        fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v))
        }
    }
}

#[cfg(feature = "std")]
mod standard_rocstr {
    extern crate std;

    use serde::de::Visitor;

    use super::RocStr;
    use super::RocStrVisitor;

    use core::fmt;
    use std::string::String;

    impl<'de, const SIZE: usize> Visitor<'de> for RocStrVisitor<SIZE> {
        type Value = RocStr<SIZE>;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a valid utf-8 string")
        }

        fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            match v {
                true => Ok(RocStr::<SIZE>::from("true")),
                false => Ok(RocStr::<SIZE>::from("false")),
            }
        }

        fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v).reshape::<SIZE>())
        }

        fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v).reshape::<SIZE>())
        }

        fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v).reshape::<SIZE>())
        }

        fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v).reshape::<SIZE>())
        }

        fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            let mut buffer = [0; 4];
            let encoded = v.encode_utf8(&mut buffer);
            Ok(RocStr::from(encoded as &str))
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v))
        }

        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v))
        }

        fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(RocStr::from(v))
        }
    }
}

mod tests {
    use super::*;

    #[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
    struct SerdeStruct {
        id: u64,
        name: RocStr<64>,
    }

    #[test]
    fn serialized_to_json_should_be_the_values_as_json() {
        let value = SerdeStruct {
            id: 42,
            name: "foo".into(),
        };

        let serialized = serde_json::to_string(&value);
        assert!(serialized.is_ok(), "❌ {}", serialized.err().unwrap());

        let serialized = serialized.unwrap();
        assert_eq!(serialized, r#"{"id":42,"name":"foo"}"#);
    }

    #[test]
    fn deserialized_from_json_should_contain_the_values() {
        let expected = SerdeStruct {
            id: 42,
            name: "foo".into(),
        };

        let deserialized = serde_json::from_str::<SerdeStruct>(r#"{"id":42,"name":"foo"}"#);

        assert!(deserialized.is_ok(), "❌ {}", deserialized.err().unwrap());

        let deserialized = deserialized.unwrap();
        assert_eq!(deserialized, expected);
    }

    #[test]
    fn serialized_to_toml_should_be_the_values_as_toml() {
        let value = SerdeStruct {
            id: 42,
            name: "foo".into(),
        };

        let serialized = toml::to_string(&value);
        assert!(serialized.is_ok(), "❌ {}", serialized.err().unwrap());

        let serialized = serialized.unwrap();
        assert_eq!(serialized, "id = 42\nname = \"foo\"\n");
    }

    #[test]
    fn deserialized_from_toml_should_contain_the_values() {
        let expected = SerdeStruct {
            id: 42,
            name: "foo".into(),
        };

        let deserialized = toml::from_str::<SerdeStruct>("id = 42\nname = \"foo\"\n");

        match deserialized {
            Ok(deserialized) => assert_eq!(deserialized, expected),
            Err(e) => panic!("❌ {e}"),
        }
    }
}