bramble-data 0.1.1

Bramble's Binary Data Format
Documentation
//! Custom serialization utilities

/// (De)serializes `Option<()>` as either null (for `None`) or true (for `Some(())`).
pub mod option_unit_as_null_or_true {
    use serde::{de, ser, Deserialize, Serialize};

    #[doc(hidden)]
    pub fn serialize<S>(value: &Option<()>, ser: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match value {
            None => ().serialize(ser),
            Some(()) => true.serialize(ser),
        }
    }

    #[doc(hidden)]
    pub fn deserialize<'de, D>(de: D) -> Result<Option<()>, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        match OptionAsNullOrTrue::deserialize(de)? {
            OptionAsNullOrTrue::Null(()) => Ok(None),
            OptionAsNullOrTrue::True(true) => Ok(Some(())),
            _ => Err(de::Error::invalid_value(
                de::Unexpected::Bool(false),
                &"null or true",
            )),
        }
    }

    #[derive(Deserialize)]
    #[serde(untagged)]
    enum OptionAsNullOrTrue {
        Null(()),
        True(bool),
    }
}

/// (De)serializes `Option<()>` as a boolean (false for `None`, true for `Some(())`).
pub mod option_unit_as_bool {
    use serde::{de, ser, Deserialize, Serialize};

    #[doc(hidden)]
    pub fn serialize<S>(value: &Option<()>, ser: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        value.is_some().serialize(ser)
    }

    #[doc(hidden)]
    pub fn deserialize<'de, D>(de: D) -> Result<Option<()>, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        Ok(if bool::deserialize(de)? {
            Some(())
        } else {
            None
        })
    }
}

/// (De)serializes `Option<()>` as a list (empty for `None`, singleton null for `Some(())`).
pub mod option_unit_as_list {
    use serde::{de, ser, Deserialize, Serialize};

    #[doc(hidden)]
    pub fn serialize<S>(value: &Option<()>, ser: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        OptionAsList { unit: *value }.serialize(ser)
    }

    #[doc(hidden)]
    pub fn deserialize<'de, D>(de: D) -> Result<Option<()>, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let o = OptionAsList::deserialize(de)?;
        Ok(o.unit)
    }

    #[derive(Serialize, Deserialize)]
    struct OptionAsList {
        #[serde(default)]
        #[serde(skip_serializing_if = "Option::is_none")]
        #[serde(deserialize_with = "deserialize_prefer_some")]
        unit: Option<()>,
    }

    fn deserialize_prefer_some<'de, D>(de: D) -> Result<Option<()>, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let _ = <()>::deserialize(de)?;
        Ok(Some(()))
    }
}

/// (De)serializes `u64` as an `i64` offset by 2^31.
pub mod u64_as_i64 {
    use serde::{de, ser, Deserialize, Serialize};

    #[doc(hidden)]
    pub fn serialize<S>(value: &u64, ser: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        i64::from_be_bytes(value.to_be_bytes()).serialize(ser)
    }

    #[doc(hidden)]
    pub fn deserialize<'de, D>(de: D) -> Result<u64, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let value = i64::deserialize(de)?;
        Ok(u64::from_be_bytes(value.to_be_bytes()))
    }
}

/// (De)serializes `u64` as raw bytes.
pub mod u64_as_bytes {
    use super::array_as_bytes::ByteArrayVisitor;
    use serde::{de, ser};

    #[doc(hidden)]
    pub fn serialize<S>(value: &u64, ser: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        ser.serialize_bytes(&value.to_be_bytes())
    }

    #[doc(hidden)]
    pub fn deserialize<'de, D>(de: D) -> Result<u64, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let bytes = de.deserialize_bytes(ByteArrayVisitor::default())?;
        Ok(u64::from_be_bytes(bytes))
    }
}

/// (De)serializes `u64` as `i64` if it fits, otherwise as raw bytes.
pub mod u64_as_i64_or_bytes {
    use serde::{de, ser, Deserialize};

    #[doc(hidden)]
    pub fn serialize<S>(value: &u64, ser: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        if *value > i64::MAX as u64 {
            super::u64_as_bytes::serialize(value, ser)
        } else {
            super::u64_as_i64::serialize(value, ser)
        }
    }

    #[doc(hidden)]
    pub fn deserialize<'de, D>(de: D) -> Result<u64, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        match U64AsI64OrRaw::deserialize(de)? {
            U64AsI64OrRaw::I64(value) if value <= i64::MAX as u64 => Ok(value as u64),
            U64AsI64OrRaw::Raw(value) if value > i64::MAX as u64 => Ok(value),
            _ => Err(de::Error::invalid_value(
                de::Unexpected::Other("out-of-bounds i64 or raw"),
                &"i64 >= 0 or raw <= i64::MAX",
            )),
        }
    }

    #[derive(Deserialize)]
    #[serde(untagged)]
    enum U64AsI64OrRaw {
        I64(u64),
        #[serde(with = "super::u64_as_bytes")]
        Raw(u64),
    }
}

/// (De)serializes arrays as raw bytes.
pub mod array_as_bytes {
    use serde::{de, ser};
    use std::{fmt, marker::PhantomData};

    #[doc(hidden)]
    pub trait CopyFromSlice: Default {
        const LENGTH: usize;
        fn copy_from_slice(&mut self, slice: &[u8]);
    }

    macro_rules! copy_from_slice_array_impl {
        ($n:literal) => {
            impl CopyFromSlice for [u8; $n] {
                const LENGTH: usize = $n;
                fn copy_from_slice(&mut self, slice: &[u8]) {
                    <[u8]>::copy_from_slice(self, slice)
                }
            }
        };
    }

    copy_from_slice_array_impl!(0);
    copy_from_slice_array_impl!(1);
    copy_from_slice_array_impl!(2);
    copy_from_slice_array_impl!(3);
    copy_from_slice_array_impl!(4);
    copy_from_slice_array_impl!(5);
    copy_from_slice_array_impl!(6);
    copy_from_slice_array_impl!(7);
    copy_from_slice_array_impl!(8);
    copy_from_slice_array_impl!(9);
    copy_from_slice_array_impl!(10);
    copy_from_slice_array_impl!(11);
    copy_from_slice_array_impl!(12);
    copy_from_slice_array_impl!(13);
    copy_from_slice_array_impl!(14);
    copy_from_slice_array_impl!(15);
    copy_from_slice_array_impl!(16);
    copy_from_slice_array_impl!(17);
    copy_from_slice_array_impl!(18);
    copy_from_slice_array_impl!(19);
    copy_from_slice_array_impl!(20);
    copy_from_slice_array_impl!(21);
    copy_from_slice_array_impl!(22);
    copy_from_slice_array_impl!(23);
    copy_from_slice_array_impl!(24);
    copy_from_slice_array_impl!(25);
    copy_from_slice_array_impl!(26);
    copy_from_slice_array_impl!(27);
    copy_from_slice_array_impl!(28);
    copy_from_slice_array_impl!(29);
    copy_from_slice_array_impl!(30);
    copy_from_slice_array_impl!(31);
    copy_from_slice_array_impl!(32);

    #[derive(Default)]
    pub(crate) struct ByteArrayVisitor<T>
    where
        T: CopyFromSlice,
    {
        array: PhantomData<T>,
    }

    impl<'de, T> de::Visitor<'de> for ByteArrayVisitor<T>
    where
        T: CopyFromSlice,
    {
        type Value = T;

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

        fn visit_bytes<E>(self, bytes: &[u8]) -> Result<T, E>
        where
            E: de::Error,
        {
            if bytes.len() != T::LENGTH {
                return Err(de::Error::invalid_length(bytes.len(), &"array size"));
            }
            let mut buf = T::default();
            buf.copy_from_slice(bytes);
            Ok(buf)
        }

        fn visit_byte_buf<E>(self, bytes: Vec<u8>) -> Result<T, E>
        where
            E: de::Error,
        {
            self.visit_bytes(&bytes)
        }
    }

    #[doc(hidden)]
    pub fn serialize<S, T>(value: &T, ser: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
        T: AsRef<[u8]>,
    {
        ser.serialize_bytes(value.as_ref())
    }

    #[doc(hidden)]
    pub fn deserialize<'de, D, T>(de: D) -> Result<T, D::Error>
    where
        D: de::Deserializer<'de>,
        T: CopyFromSlice,
    {
        de.deserialize_bytes(ByteArrayVisitor::default())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::from_slice;
    use crate::to_vec;
    use hex_literal::hex;
    use serde::{Deserialize, Serialize};

    #[test]
    fn customize_option_unit() {
        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
        struct Test {
            #[serde(with = "option_unit_as_null_or_true")]
            a0: Option<()>,
            #[serde(with = "option_unit_as_null_or_true")]
            a1: Option<()>,
            #[serde(with = "option_unit_as_bool")]
            b0: Option<()>,
            #[serde(with = "option_unit_as_bool")]
            b1: Option<()>,
            #[serde(with = "option_unit_as_list")]
            c0: Option<()>,
            #[serde(with = "option_unit_as_list")]
            c1: Option<()>,
        }
        let input = Test {
            a0: None,
            a1: Some(()),
            b0: None,
            b1: Some(()),
            c0: None,
            c1: Some(()),
        };
        let buf = to_vec(&input).unwrap();
        assert_eq!(
            hex!("60 00 11 10 11 60 80 60 00 80 80").as_ref(),
            buf.as_slice()
        );

        let output = from_slice(&buf).unwrap();

        assert_eq!(input, output);
    }

    #[test]
    fn customize_u64() {
        #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
        struct Test {
            #[serde(with = "u64_as_i64")]
            a0: u64,
            #[serde(with = "u64_as_i64")]
            a1: u64,
            #[serde(with = "u64_as_bytes")]
            b0: u64,
            #[serde(with = "u64_as_bytes")]
            b1: u64,
            #[serde(with = "u64_as_i64_or_bytes")]
            c0: u64,
            #[serde(with = "u64_as_i64_or_bytes")]
            c1: u64,
        }
        let input = Test {
            a0: 17,
            a1: 0x8765432101234567,
            b0: 17,
            b1: 0x8765432101234567,
            c0: 17,
            c1: 0x8765432101234567,
        };
        let buf = to_vec(&input).unwrap();
        assert_eq!(
            hex!("60 2111 288765432101234567 51080000000000000011 51088765432101234567 2111 51088765432101234567 80").as_ref(),
            buf.as_slice()
        );

        let output = from_slice(&buf).unwrap();

        assert_eq!(input, output);
    }
}