tari_bor 0.13.0

The binary object representation (BOR) crate provides a binary encoding for template/engine data types
Documentation
//   Copyright 2023 The Tari Project
//   SPDX-License-Identifier: BSD-3-Clause

//! This module provides a wrapper for serializing and deserializing `Value`. This is "generated" from the serde derive
//! macros and copied here. This allows the enum to be encoded as JSON representation of the ciborium::Value enum
//! as if the derive macros were used, instead of the de/serializers implemented by ciborium which encode the CBOR value
//! in a non-standard way for JSON.

use core::{fmt, fmt::Formatter, marker::PhantomData};

use ciborium::{Value, value::Integer};
use serde::{de::VariantAccess, ser::SerializeTupleVariant};

pub struct CborValueSerializeFixWrapper<'a>(pub &'a Value);

impl serde::Serialize for CborValueSerializeFixWrapper<'_> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: serde::Serializer {
        match &self.0 {
            Value::Integer(field0) => {
                let value = i128::from(*field0);
                serializer.serialize_newtype_variant("Value", 0u32, "Integer", &value)
            },
            Value::Bytes(field0) => {
                serde::Serializer::serialize_newtype_variant(serializer, "Value", 1u32, "Bytes", field0)
            },
            Value::Float(field0) => {
                serde::Serializer::serialize_newtype_variant(serializer, "Value", 2u32, "Float", field0)
            },
            Value::Text(field0) => {
                serde::Serializer::serialize_newtype_variant(serializer, "Value", 3u32, "Text", field0)
            },
            Value::Bool(field0) => {
                serde::Serializer::serialize_newtype_variant(serializer, "Value", 4u32, "Bool", field0)
            },
            Value::Null => serde::Serializer::serialize_unit_variant(serializer, "Value", 5u32, "Null"),
            Value::Tag(tag, value) => {
                let mut state = serde::Serializer::serialize_tuple_variant(serializer, "Value", 6u32, "Tag", 2)?;
                SerializeTupleVariant::serialize_field(&mut state, tag)?;
                SerializeTupleVariant::serialize_field(&mut state, &Self(value))?;
                SerializeTupleVariant::end(state)
            },
            Value::Array(arr) => {
                let wrapped = arr.iter().map(Self).collect::<Vec<_>>();
                serde::Serializer::serialize_newtype_variant(serializer, "Value", 7u32, "Array", &wrapped)
            },
            Value::Map(map) => {
                let wrapped = map.iter().map(|(k, v)| (Self(k), Self(v))).collect::<Vec<_>>();
                serde::Serializer::serialize_newtype_variant(serializer, "Value", 8u32, "Map", &wrapped)
            },
            ref v => Err(serde::ser::Error::custom(format!("invalid value {v:?}"))),
        }
    }
}

pub struct CborValueDeserializeFixWrapper(pub Value);

impl CborValueDeserializeFixWrapper {
    pub fn into_inner(self) -> Value {
        self.0
    }
}

impl<'de> serde::Deserialize<'de> for CborValueDeserializeFixWrapper {
    #[allow(clippy::too_many_lines)]
    fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
    where __D: serde::Deserializer<'de> {
        #[allow(non_camel_case_types)]
        #[doc(hidden)]
        enum __Field {
            Integer,
            Bytes,
            Float,
            Text,
            Bool,
            Null,
            Tag,
            Array,
            Map,
        }
        #[doc(hidden)]
        struct __FieldVisitor;
        impl serde::de::Visitor<'_> for __FieldVisitor {
            type Value = __Field;

            fn expecting(&self, __formatter: &mut Formatter) -> fmt::Result {
                Formatter::write_str(__formatter, "variant identifier")
            }

            fn visit_u64<__E>(self, __value: u64) -> Result<Self::Value, __E>
            where __E: serde::de::Error {
                match __value {
                    0u64 => Ok(__Field::Integer),
                    1u64 => Ok(__Field::Bytes),
                    2u64 => Ok(__Field::Float),
                    3u64 => Ok(__Field::Text),
                    4u64 => Ok(__Field::Bool),
                    5u64 => Ok(__Field::Null),
                    6u64 => Ok(__Field::Tag),
                    7u64 => Ok(__Field::Array),
                    8u64 => Ok(__Field::Map),
                    _ => Err(serde::de::Error::invalid_value(
                        serde::de::Unexpected::Unsigned(__value),
                        &"variant index 0 <= i < 9",
                    )),
                }
            }

            fn visit_str<__E>(self, __value: &str) -> Result<Self::Value, __E>
            where __E: serde::de::Error {
                match __value {
                    "Integer" => Ok(__Field::Integer),
                    "Bytes" => Ok(__Field::Bytes),
                    "Float" => Ok(__Field::Float),
                    "Text" => Ok(__Field::Text),
                    "Bool" => Ok(__Field::Bool),
                    "Null" => Ok(__Field::Null),
                    "Tag" => Ok(__Field::Tag),
                    "Array" => Ok(__Field::Array),
                    "Map" => Ok(__Field::Map),
                    _ => Err(serde::de::Error::unknown_variant(__value, VARIANTS)),
                }
            }

            fn visit_bytes<__E>(self, __value: &[u8]) -> Result<Self::Value, __E>
            where __E: serde::de::Error {
                match __value {
                    b"Integer" => Ok(__Field::Integer),
                    b"Bytes" => Ok(__Field::Bytes),
                    b"Float" => Ok(__Field::Float),
                    b"Text" => Ok(__Field::Text),
                    b"Bool" => Ok(__Field::Bool),
                    b"Null" => Ok(__Field::Null),
                    b"Tag" => Ok(__Field::Tag),
                    b"Array" => Ok(__Field::Array),
                    b"Map" => Ok(__Field::Map),
                    _ => {
                        let __value = String::from_utf8_lossy(__value);
                        Err(serde::de::Error::unknown_variant(&__value, VARIANTS))
                    },
                }
            }
        }
        impl<'de> serde::Deserialize<'de> for __Field {
            #[inline]
            fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
            where __D: serde::Deserializer<'de> {
                serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
            }
        }
        #[doc(hidden)]
        struct __Visitor<'de> {
            marker: PhantomData<CborValueDeserializeFixWrapper>,
            lifetime: PhantomData<&'de ()>,
        }
        impl<'de> serde::de::Visitor<'de> for __Visitor<'de> {
            type Value = CborValueDeserializeFixWrapper;

            fn expecting(&self, __formatter: &mut Formatter) -> fmt::Result {
                Formatter::write_str(__formatter, "enum Value")
            }

            fn visit_enum<__A>(self, __data: __A) -> Result<Self::Value, __A::Error>
            where __A: serde::de::EnumAccess<'de> {
                match serde::de::EnumAccess::variant(__data)? {
                    (__Field::Integer, variant) => {
                        let int = variant.newtype_variant::<i128>()?;
                        Ok(CborValueDeserializeFixWrapper(Value::Integer(
                            Integer::try_from(int).map_err(serde::de::Error::custom)?,
                        )))
                    },
                    (__Field::Bytes, variant) => variant
                        .newtype_variant()
                        .map(Value::Bytes)
                        .map(CborValueDeserializeFixWrapper),
                    (__Field::Float, variant) => variant
                        .newtype_variant()
                        .map(Value::Float)
                        .map(CborValueDeserializeFixWrapper),
                    (__Field::Text, variant) => variant
                        .newtype_variant()
                        .map(Value::Text)
                        .map(CborValueDeserializeFixWrapper),
                    (__Field::Bool, variant) => variant
                        .newtype_variant()
                        .map(Value::Bool)
                        .map(CborValueDeserializeFixWrapper),
                    (__Field::Null, variant) => {
                        variant.unit_variant()?;
                        Ok(CborValueDeserializeFixWrapper(Value::Null))
                    },
                    (__Field::Tag, variant) => {
                        #[doc(hidden)]
                        struct __Visitor<'de> {
                            marker: PhantomData<CborValueDeserializeFixWrapper>,
                            lifetime: PhantomData<&'de ()>,
                        }
                        impl<'de> serde::de::Visitor<'de> for __Visitor<'de> {
                            type Value = CborValueDeserializeFixWrapper;

                            fn expecting(&self, __formatter: &mut Formatter) -> fmt::Result {
                                Formatter::write_str(__formatter, "tuple variant Value::Tag")
                            }

                            #[inline]
                            fn visit_seq<__A>(self, mut __seq: __A) -> Result<Self::Value, __A::Error>
                            where __A: serde::de::SeqAccess<'de> {
                                let __field0 = match serde::de::SeqAccess::next_element::<u64>(&mut __seq)? {
                                    Some(__value) => __value,
                                    None => {
                                        return Err(serde::de::Error::invalid_length(
                                            0usize,
                                            &"tuple variant Value::Tag with 2 elements",
                                        ));
                                    },
                                };
                                let wrapped =
                                    serde::de::SeqAccess::next_element::<CborValueDeserializeFixWrapper>(&mut __seq)?
                                        .ok_or_else(|| {
                                        serde::de::Error::invalid_length(
                                            1usize,
                                            &"tuple variant Value::Tag with 2 elements",
                                        )
                                    })?;
                                Ok(CborValueDeserializeFixWrapper(Value::Tag(
                                    __field0,
                                    Box::new(wrapped.0),
                                )))
                            }
                        }
                        VariantAccess::tuple_variant(variant, 2usize, __Visitor {
                            marker: PhantomData,
                            lifetime: PhantomData,
                        })
                    },
                    (__Field::Array, __variant) => {
                        let values = __variant.newtype_variant::<Vec<CborValueDeserializeFixWrapper>>()?;
                        Ok(CborValueDeserializeFixWrapper(Value::Array(
                            values.into_iter().map(|v| v.0).collect(),
                        )))
                    },
                    (__Field::Map, __variant) => {
                        let values = __variant
                            .newtype_variant::<Vec<(CborValueDeserializeFixWrapper, CborValueDeserializeFixWrapper)>>(
                            )?;
                        Ok(CborValueDeserializeFixWrapper(Value::Map(
                            values.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
                        )))
                    },
                }
            }
        }
        #[doc(hidden)]
        const VARIANTS: &[&str] = &[
            "Integer", "Bytes", "Float", "Text", "Bool", "Null", "Tag", "Array", "Map",
        ];
        serde::Deserializer::deserialize_enum(__deserializer, "Value", VARIANTS, __Visitor {
            marker: PhantomData,
            lifetime: PhantomData,
        })
    }
}

#[cfg(test)]
mod tests {
    use ciborium::cbor;

    use super::*;

    fn sample() -> Value {
        let bytes = [1u8; 32];
        cbor!({
            "code" => 415,
            "message" => null,
            "continue" => false,
            // Non-string keys
            "bytes" => bytes,
            "array" => [{()=>1}, {123=>2}, {cbor!({"A"=>1}).unwrap()=>3}],
            "extra" => { "numbers" => [8.2341e+4, 0.251425] },
        })
        .unwrap()
    }

    #[test]
    fn decode_encode() {
        let sample = sample();
        let s1 = serde_json::to_string(&CborValueSerializeFixWrapper(&sample)).unwrap();
        let decoded = serde_json::from_str::<CborValueDeserializeFixWrapper>(&s1).unwrap();
        // Decoded value matches original
        assert_eq!(sample, decoded.0);
        let s2 = serde_json::to_string(&CborValueSerializeFixWrapper(&decoded.0)).unwrap();
        // Re-encode to string, which should be identical to the previously encoded JSON string
        assert_eq!(s1, s2);
    }

    #[test]
    fn decode_encode_bincode() {
        const BINCODE_STD: bincode::config::Configuration = bincode::config::standard();
        let sample = sample();
        let s1 = bincode::serde::encode_to_vec(CborValueSerializeFixWrapper(&sample), BINCODE_STD).unwrap();
        let (decoded, _) =
            bincode::serde::decode_from_slice::<CborValueDeserializeFixWrapper, _>(&s1, BINCODE_STD).unwrap();
        // Decoded value matches original
        assert_eq!(sample, decoded.0);
        let s2 = bincode::serde::encode_to_vec(CborValueSerializeFixWrapper(&decoded.0), BINCODE_STD).unwrap();
        // Re-encode to string, which should be identical to the previously encoded JSON string
        assert_eq!(s1, s2);
    }
}