dmap 0.2.1

Parse and serialize Apple's DMAP format.
Documentation
use serde::de;
use serde::ser::{self, SerializeMap};

use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DmapItem<'a, 'k> {
    pub name: ItemName<'k>,
    pub value: DmapValue<'a, 'k>
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DmapValue<'a, 'k> {
    I8(i8),
    U8(u8),
    I16(i16),
    U16(u16),
    I32(i32),
    U32(u32),
    I64(i64),
    U64(u64),
    String(&'a str),
    Container(Vec<DmapItem<'a, 'k>>),
    Unknown(&'a [u8]),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ItemName<'k> {
    Name(&'k str),
    Code([u8; 4]),
}

impl<'de> de::Deserialize<'de> for DmapItem<'de, 'de> {
    fn deserialize<D>(deserializer: D) -> Result<DmapItem<'de, 'de>, D::Error>
        where D: de::Deserializer<'de>
    {
        struct ItemVisitor;

        impl<'de> de::Visitor<'de> for ItemVisitor {
            type Value = DmapItem<'de, 'de>;

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

            fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
                where V: de::MapAccess<'de>
            {
                use serde::de::Error;
                if let Some((k, v)) = visitor.next_entry()? {
                    Ok(DmapItem { name: k, value: v })
                } else {
                    Err(V::Error::custom("failed to get entry"))
                }
            }
        }

        deserializer.deserialize_map(ItemVisitor)
    }
}

impl<'de> de::Deserialize<'de> for ItemName<'de> {
    fn deserialize<D>(deserializer: D) -> Result<ItemName<'de>, D::Error>
        where D: de::Deserializer<'de>
    {
        struct ItemNameVisitor;

        impl<'de> de::Visitor<'de> for ItemNameVisitor {
            type Value = ItemName<'de>;

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

            fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E> {
                Ok(ItemName::Name(value))
            }

            fn visit_borrowed_bytes<E>(self, value: &'de [u8]) -> Result<Self::Value, E> {
                let mut buf = [0; 4];
                buf.copy_from_slice(value);
                Ok(ItemName::Code(buf))
            }
        }

        deserializer.deserialize_any(ItemNameVisitor)
    }
}


impl<'de> de::Deserialize<'de> for DmapValue<'de, 'de> {
    fn deserialize<D>(deserializer: D) -> Result<DmapValue<'de, 'de>, D::Error>
        where D: de::Deserializer<'de>
    {
        struct ValueVisitor;

        impl<'de> de::Visitor<'de> for ValueVisitor {
            type Value = DmapValue<'de, 'de>;

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

            fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E> {
                Ok(DmapValue::I8(value))
            }

            fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E> {
                Ok(DmapValue::U8(value))
            }

            fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E> {
                Ok(DmapValue::I16(value))
            }

            fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E> {
                Ok(DmapValue::U16(value))
            }

            fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E> {
                Ok(DmapValue::I32(value))
            }
            
            fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E> {
                Ok(DmapValue::U32(value))
            }

            fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
                Ok(DmapValue::I64(value))
            }
            
            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
                Ok(DmapValue::U64(value))
            }

            fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E> {
                Ok(DmapValue::String(value))
            }

            fn visit_borrowed_bytes<E>(self, value: &'de [u8]) -> Result<Self::Value, E> {
                Ok(DmapValue::Unknown(value))
            }

            fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
                where V: de::MapAccess<'de>
            {
                let mut vec = Vec::new();

                while let Some((k, v)) = visitor.next_entry()? {
                    vec.push(DmapItem {
                        name: k,
                        value: v,
                    });
                }

                Ok(DmapValue::Container(vec))
            }
        }

        deserializer.deserialize_any(ValueVisitor)
    }
}

impl<'a, 'k> ser::Serialize for DmapItem<'a, 'k> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        let mut map = serializer.serialize_map(Some(1))?;
        map.serialize_entry(&self.name, &self.value)?;
        map.end()
    }
}

impl<'k> ser::Serialize for ItemName<'k> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        match *self {
            ItemName::Name(n) => serializer.serialize_str(n),
            ItemName::Code(c) => serializer.serialize_bytes(&c),
        }
    }
}

impl<'a, 'k> ser::Serialize for DmapValue<'a, 'k> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        match *self {
            DmapValue::I8(x) => serializer.serialize_i8(x),
            DmapValue::U8(x) => serializer.serialize_u8(x),
            DmapValue::I16(x) => serializer.serialize_i16(x),
            DmapValue::U16(x) => serializer.serialize_u16(x),
            DmapValue::I32(x) => serializer.serialize_i32(x),
            DmapValue::U32(x) => serializer.serialize_u32(x),
            DmapValue::I64(x) => serializer.serialize_i64(x),
            DmapValue::U64(x) => serializer.serialize_u64(x),
            DmapValue::String(s) => serializer.serialize_str(s),
            DmapValue::Unknown(b) => serializer.serialize_bytes(b),
            DmapValue::Container(ref c) => {
                let mut map = serializer.serialize_map(Some(c.len()))?;
                for e in c {
                    map.serialize_entry(&e.name, &e.value)?;
                }
                map.end()
            }
        }
    }
}