jdrouet/mrml

View on GitHub
packages/mrml-core/src/prelude/json.rs

Summary

Maintainability
Test Coverage
use std::hash::Hash;
use std::marker::PhantomData;

use serde::de::{MapAccess, Unexpected};
use serde::ser::SerializeMap;

use super::hash::Map;
use super::{Component, StaticTag};

pub trait JsonAttributes: serde::Serialize {
    fn has_attributes(&self) -> bool;
    fn try_from_serde<Err: serde::de::Error>(this: Option<Self>) -> Result<Self, Err>
    where
        Self: Sized;
}

impl JsonAttributes for () {
    #[inline]
    fn has_attributes(&self) -> bool {
        false
    }

    fn try_from_serde<Err: serde::de::Error>(_: Option<Self>) -> Result<Self, Err>
    where
        Self: Sized,
    {
        Ok(())
    }
}

impl<K: Hash + Eq + Default + serde::Serialize, V: Default + serde::Serialize> JsonAttributes
    for Map<K, V>
{
    #[inline]
    fn has_attributes(&self) -> bool {
        !self.is_empty()
    }

    fn try_from_serde<Err: serde::de::Error>(this: Option<Self>) -> Result<Self, Err>
    where
        Self: Sized,
    {
        Ok(this.unwrap_or_default())
    }
}

pub trait JsonChildren: serde::Serialize {
    fn has_children(&self) -> bool;

    fn try_from_serde<Err: serde::de::Error>(this: Option<Self>) -> Result<Self, Err>
    where
        Self: Sized;
}

impl JsonChildren for () {
    #[inline]
    fn has_children(&self) -> bool {
        false
    }

    fn try_from_serde<Err: serde::de::Error>(_: Option<Self>) -> Result<Self, Err>
    where
        Self: Sized,
    {
        Ok(())
    }
}

impl<V: serde::Serialize> JsonChildren for Vec<V> {
    #[inline]
    fn has_children(&self) -> bool {
        !self.is_empty()
    }

    fn try_from_serde<Err: serde::de::Error>(this: Option<Self>) -> Result<Self, Err>
    where
        Self: Sized,
    {
        Ok(this.unwrap_or_default())
    }
}

impl JsonChildren for String {
    #[inline]
    fn has_children(&self) -> bool {
        !self.is_empty()
    }

    fn try_from_serde<Err: serde::de::Error>(this: Option<Self>) -> Result<Self, Err>
    where
        Self: Sized,
    {
        Ok(this.unwrap_or_default())
    }
}

pub(crate) struct DeserializableTag<T>(pub T);

impl<'de> serde::de::Deserialize<'de> for DeserializableTag<String> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        Ok(Self(String::deserialize(deserializer)?))
    }
}

impl<'de, T: StaticTag> serde::de::Deserialize<'de> for DeserializableTag<PhantomData<T>> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let value = String::deserialize(deserializer)?;
        let expected = T::static_tag();
        if value != expected {
            Err(serde::de::Error::invalid_value(
                Unexpected::Str(&value),
                &expected,
            ))
        } else {
            Ok(Self(PhantomData::<T>))
        }
    }
}

impl<Child: serde::Serialize> serde::Serialize
    for super::Component<String, crate::prelude::AttributeMap, Vec<Child>>
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let mut map = serializer.serialize_map(Some(3))?;
        map.serialize_entry("type", self.tag.as_str())?;
        if !self.attributes.is_empty() {
            map.serialize_entry("attributes", &self.attributes)?;
        }
        if !self.children.is_empty() {
            map.serialize_entry("children", &self.children)?;
        }
        map.end()
    }
}

impl<Tag: StaticTag, Attributes: JsonAttributes, Children: JsonChildren> serde::Serialize
    for super::Component<PhantomData<Tag>, Attributes, Children>
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let mut map = serializer.serialize_map(Some(3))?;
        map.serialize_entry("type", Tag::static_tag())?;
        if self.attributes.has_attributes() {
            map.serialize_entry("attributes", &self.attributes)?;
        }
        if self.children.has_children() {
            map.serialize_entry("children", &self.children)?;
        }
        map.end()
    }
}

struct ComponentAsMapVisitor<Tag, Attributes, Children> {
    tag: PhantomData<Tag>,
    attributes: PhantomData<Attributes>,
    children: PhantomData<Children>,
}

impl<Tag, Attributes, Children> Default for ComponentAsMapVisitor<Tag, Attributes, Children> {
    fn default() -> Self {
        Self {
            tag: PhantomData::<Tag>,
            attributes: PhantomData::<Attributes>,
            children: PhantomData::<Children>,
        }
    }
}

impl<'de, Tag, Attributes, Children> serde::de::Deserialize<'de>
    for super::Component<Tag, Attributes, Children>
where
    DeserializableTag<Tag>: serde::de::Deserialize<'de>,
    Attributes: JsonAttributes + serde::de::Deserialize<'de>,
    Children: JsonChildren + serde::de::Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_map(ComponentAsMapVisitor::<Tag, Attributes, Children>::default())
    }
}

#[derive(serde::Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum ComponentField {
    Type,
    Attributes,
    Children,
}

impl<'de, Tag, Attributes, Children> serde::de::Visitor<'de>
    for ComponentAsMapVisitor<Tag, Attributes, Children>
where
    DeserializableTag<Tag>: serde::de::Deserialize<'de>,
    Attributes: JsonAttributes + serde::de::Deserialize<'de>,
    Children: JsonChildren + serde::de::Deserialize<'de>,
{
    type Value = super::Component<Tag, Attributes, Children>;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("struct Component")
    }

    fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
    where
        V: MapAccess<'de>,
    {
        let mut rtype: Option<Tag> = None;
        let mut attributes: Option<Attributes> = None;
        let mut children: Option<Children> = None;

        while let Some(key) = map.next_key()? {
            match key {
                ComponentField::Type if rtype.is_some() => {
                    return Err(serde::de::Error::duplicate_field("type"));
                }
                ComponentField::Type => {
                    let DeserializableTag(tag) = map.next_value()?;
                    rtype = Some(tag);
                }
                ComponentField::Attributes if attributes.is_some() => {
                    return Err(serde::de::Error::duplicate_field("attributes"));
                }
                ComponentField::Attributes => {
                    attributes = Some(map.next_value()?);
                }
                ComponentField::Children if children.is_some() => {
                    return Err(serde::de::Error::duplicate_field("children"));
                }
                ComponentField::Children => {
                    children = Some(map.next_value()?);
                }
            }
        }

        let rtype = rtype.ok_or_else(|| serde::de::Error::missing_field("type"))?;
        Ok(Component {
            tag: rtype,
            attributes: Attributes::try_from_serde(attributes)?,
            children: Children::try_from_serde(children)?,
        })
    }
}