valuable-serde-0.1.0/.cargo_vcs_info.json0000644000000001540000000000100137250ustar { "git": { "sha1": "1fc2ad50fcae7fc0da81dc40a385c235636ba525" }, "path_in_vcs": "valuable-serde" }valuable-serde-0.1.0/CHANGELOG.md000064400000000000000000000000470072674642500143570ustar 00000000000000# 0.1.0 (2022-01-26) - Initial releasevaluable-serde-0.1.0/Cargo.toml0000644000000025270000000000100117310ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.51.0" name = "valuable-serde" version = "0.1.0" authors = ["Taiki Endo "] description = "`serde::Serialize` implementation for `Valuable` types." readme = "README.md" keywords = ["valuable", "serialization", "serde", "no_std"] categories = ["development-tools::debugging", "encoding"] license = "MIT" repository = "https://github.com/tokio-rs/valuable" resolver = "2" [dependencies.serde] version = "1.0.103" default-features = false [dependencies.valuable] version = "0.1" default-features = false [dev-dependencies.serde] version = "1" features = ["derive"] [dev-dependencies.serde_json] version = "1" [dev-dependencies.serde_test] version = "1" [dev-dependencies.valuable] version = "0.1" features = ["derive"] [features] alloc = ["valuable/alloc", "serde/alloc"] default = ["std"] std = ["alloc", "valuable/std", "serde/std"] valuable-serde-0.1.0/Cargo.toml.orig000064400000000000000000000016020072674642500154330ustar 00000000000000[package] name = "valuable-serde" version = "0.1.0" authors = ["Taiki Endo "] edition = "2018" license = "MIT" description = "`serde::Serialize` implementation for `Valuable` types." rust-version = "1.51.0" readme = "README.md" repository = "https://github.com/tokio-rs/valuable" categories = [ "development-tools::debugging", "encoding", ] keywords = [ "valuable", "serialization", "serde", "no_std", ] [features] default = ["std"] std = ["alloc", "valuable/std", "serde/std"] alloc = ["valuable/alloc", "serde/alloc"] [dependencies] valuable = { version = "0.1", path = "../valuable", default-features = false } serde = { version = "1.0.103", default-features = false } [dev-dependencies] valuable = { version = "0.1", path = "../valuable", features = ["derive"] } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_test = "1" valuable-serde-0.1.0/README.md000064400000000000000000000020450072674642500140250ustar 00000000000000# valuable-serde [Valuable][`valuable`] provides object-safe value inspection. Use cases include passing structured data to trait objects and object-safe serialization. This crate provides a bridge between [`valuable`] and the [`serde`] serialization ecosystem. Using [`valuable_serde::Serializable`] allows any type that implements `valuable`'s [`Valuable`] trait to be serialized by any [`serde::ser::Serializer`]. [`valuable`]: https://crates.io/crates/valuable [`serde`]: https://crates.io/crates/serde [`valuable_serde::Serializable`]: https://docs.rs/valuable-serde/latest/valuable_serde/struct.Serializable.html [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html [`serde::ser::Serializer`]: https://docs.rs/serde/latest/serde/ser/trait.Serializer.html ## License This project is licensed under the [MIT license](LICENSE). ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Valuable by you, shall be licensed as MIT, without any additional terms or conditions.valuable-serde-0.1.0/src/lib.rs000064400000000000000000000541640072674642500144620ustar 00000000000000#![warn( missing_debug_implementations, missing_docs, rust_2018_idioms, unreachable_pub )] #![cfg_attr(not(feature = "std"), no_std)] //! [`serde::Serialize`] implementation for [`Valuable`] types. //! //! [Valuable][`valuable`] provides object-safe value inspection. Use cases //! include passing structured data to trait objects and object-safe serialization. //! //! This crate provides a bridge between [`valuable`] and the [`serde`] //! serialization ecosystem. Using [`Serializable`] allows any type //! that implements `valuable`'s [`Valuable`] trait to be serialized by any //! [`serde::ser::Serializer`]. //! //! [`valuable`]: https://docs.rs/valuable //! [`serde`]: https://docs.rs/serde //! //! # Examples //! //! ``` //! use valuable::Valuable; //! use valuable_serde::Serializable; //! //! #[derive(Valuable)] //! struct Point { //! x: i32, //! y: i32, //! } //! //! let point = Point { x: 1, y: 2 }; //! //! let value = Serializable::new(&point); //! //! assert_eq!( //! serde_json::to_string(&value).unwrap(), //! r#"{"x":1,"y":2}"#, //! ); //! ``` use core::{fmt, mem}; use serde::ser::{ Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, }; use serde::{Serialize, Serializer}; use valuable::{ EnumDef, Fields, NamedValues, StructDef, TupleDef, Valuable, Value, Variant, VariantDef, Visit, }; /// A wrapper around [`Valuable`] types that implements [`Serialize`]. pub struct Serializable(V); impl Serializable where V: Valuable, { /// Creates a new `Serializable`. pub fn new(v: V) -> Self { Self(v) } /// Returns a reference to the underlying value. pub fn get_ref(&self) -> &V { &self.0 } /// Returns a mutable reference to the underlying value. pub fn get_mut(&mut self) -> &mut V { &mut self.0 } /// Unwraps this `Serializable`, returning the underlying value. pub fn into_inner(self) -> V { self.0 } } impl fmt::Debug for Serializable where V: Valuable, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.as_value(), f) } } impl Valuable for Serializable where V: Valuable, { fn as_value(&self) -> Value<'_> { self.0.as_value() } fn visit(&self, visit: &mut dyn Visit) { self.0.visit(visit); } } impl Serialize for Serializable where V: Valuable, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match self.0.as_value() { Value::Bool(b) => serializer.serialize_bool(b), Value::I8(n) => serializer.serialize_i8(n), Value::I16(n) => serializer.serialize_i16(n), Value::I32(n) => serializer.serialize_i32(n), Value::I64(n) => serializer.serialize_i64(n), Value::I128(n) => serializer.serialize_i128(n), Value::Isize(n) => serializer.serialize_i64(n as _), Value::U8(n) => serializer.serialize_u8(n), Value::U16(n) => serializer.serialize_u16(n), Value::U32(n) => serializer.serialize_u32(n), Value::U64(n) => serializer.serialize_u64(n), Value::U128(n) => serializer.serialize_u128(n), Value::Usize(n) => serializer.serialize_u64(n as _), Value::F32(n) => serializer.serialize_f32(n), Value::F64(n) => serializer.serialize_f64(n), Value::Char(c) => serializer.serialize_char(c), Value::String(s) => serializer.serialize_str(s), Value::Unit => serializer.serialize_unit(), Value::Listable(l) => { let size_hint = l.size_hint(); let mut ser = serializer.serialize_seq(Some(size_hint.1.unwrap_or(size_hint.0)))?; let mut visitor = VisitList::::Serializer(&mut ser); l.visit(&mut visitor); if let VisitList::Error(e) = visitor { return Err(e); } ser.end() } Value::Mappable(m) => { let size_hint = m.size_hint(); let mut ser = serializer.serialize_map(size_hint.1)?; let mut visitor = VisitMap::::Serializer(&mut ser); m.visit(&mut visitor); if let VisitMap::Error(e) = visitor { return Err(e); } ser.end() } Value::Structable(s) => match s.definition() { StructDef::Static { name, fields, .. } => { let mut visitor = VisitStaticStruct::Start { name, fields, serializer, }; s.visit(&mut visitor); match visitor { VisitStaticStruct::End(res) => res, _ => unreachable!(), } } StructDef::Dynamic { fields, .. } => { if fields.is_named() { // TODO: size_hint? let mut ser = serializer.serialize_map(None)?; let mut visitor = VisitDynamic::::NamedFields(&mut ser); s.visit(&mut visitor); if let VisitDynamic::Error(e) = visitor { return Err(e); } ser.end() } else { // TODO: size_hint? let mut ser = serializer.serialize_seq(None)?; let mut visitor = VisitDynamic::::UnnamedFields(&mut ser); s.visit(&mut visitor); if let VisitDynamic::Error(e) = visitor { return Err(e); } ser.end() } } def => unreachable!("{:?}", def), }, Value::Enumerable(e) => match (e.definition(), e.variant()) { ( EnumDef::Static { name, variants: def, .. }, Variant::Static(variant), ) => { let mut visitor = VisitStaticEnum::Start { name, def, variant, serializer, }; e.visit(&mut visitor); match visitor { VisitStaticEnum::End(res) => res, _ => unreachable!(), } } (EnumDef::Dynamic { .. }, variant) => { if variant.is_named_fields() { // TODO: size_hint? let mut ser = serializer.serialize_map(None)?; let mut visitor = VisitDynamic::::NamedFields(&mut ser); e.visit(&mut visitor); if let VisitDynamic::Error(e) = visitor { return Err(e); } ser.end() } else { // TODO: size_hint? let mut ser = serializer.serialize_seq(None)?; let mut visitor = VisitDynamic::::UnnamedFields(&mut ser); e.visit(&mut visitor); if let VisitDynamic::Error(e) = visitor { return Err(e); } ser.end() } } (EnumDef::Static { .. }, Variant::Dynamic(..)) => { Err(S::Error::custom("dynamic variant in static enum")) } def => unreachable!("{:?}", def), }, Value::Tuplable(t) => { let def = t.definition(); if def.is_unit() { return serializer.serialize_unit(); } match def { TupleDef::Static { fields: len, .. } => { let ser = serializer.serialize_tuple(len)?; let mut visitor = VisitStaticTuple::::Start(ser); t.visit(&mut visitor); match visitor { VisitStaticTuple::End(res) => res, _ => unreachable!(), } } TupleDef::Dynamic { fields: size_hint, .. } => { let mut ser = serializer.serialize_seq(size_hint.1)?; let mut visitor = VisitDynamic::::UnnamedFields(&mut ser); t.visit(&mut visitor); if let VisitDynamic::Error(e) = visitor { return Err(e); } ser.end() } def => unreachable!("{:?}", def), } } #[cfg(feature = "std")] Value::Path(p) => Serialize::serialize(p, serializer), #[cfg(feature = "std")] Value::Error(e) => Err(S::Error::custom(e)), v => unimplemented!("{:?}", v), } } } enum VisitList<'a, S: Serializer> { Serializer(&'a mut S::SerializeSeq), Error(S::Error), } impl Visit for VisitList<'_, S> { fn visit_value(&mut self, value: Value<'_>) { if let Self::Serializer(ser) = self { if let Err(e) = ser.serialize_element(&Serializable(value)) { *self = Self::Error(e); } } } fn visit_entry(&mut self, _: Value<'_>, _: Value<'_>) { if !matches!(self, Self::Error(..)) { *self = Self::Error(S::Error::custom("visit_entry in list")); } } fn visit_named_fields(&mut self, _: &NamedValues<'_>) { if !matches!(self, Self::Error(..)) { *self = Self::Error(S::Error::custom("visit_named_fields in list")); } } fn visit_unnamed_fields(&mut self, _: &[Value<'_>]) { if !matches!(self, Self::Error(..)) { *self = Self::Error(S::Error::custom("visit_unnamed_fields in list")); } } } enum VisitMap<'a, S: Serializer> { Serializer(&'a mut S::SerializeMap), Error(S::Error), } impl Visit for VisitMap<'_, S> { fn visit_entry(&mut self, key: Value<'_>, value: Value<'_>) { if let Self::Serializer(ser) = self { if let Err(e) = ser.serialize_entry(&Serializable(key), &Serializable(value)) { *self = Self::Error(e); } } } fn visit_value(&mut self, _: Value<'_>) { if !matches!(self, Self::Error(..)) { *self = Self::Error(S::Error::custom("visit_value in map")); } } fn visit_named_fields(&mut self, _: &NamedValues<'_>) { if !matches!(self, Self::Error(..)) { *self = Self::Error(S::Error::custom("visit_named_fields in map")); } } fn visit_unnamed_fields(&mut self, _: &[Value<'_>]) { if !matches!(self, Self::Error(..)) { *self = Self::Error(S::Error::custom("visit_unnamed_fields in map")); } } } enum VisitStaticStruct { Start { name: &'static str, fields: Fields<'static>, serializer: S, }, End(Result), Tmp, } impl Visit for VisitStaticStruct { fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) { let (name, fields, serializer) = match mem::replace(self, Self::Tmp) { Self::Start { name, fields: Fields::Named(fields), serializer, } => (name, fields, serializer), mut res @ Self::End(..) => { if matches!(res, Self::End(Ok(..))) { res = Self::End(Err(S::Error::custom( "visit_named_fields called multiple times in static struct", ))); } *self = res; return; } _ => unreachable!(), }; let mut ser = match serializer.serialize_struct(name, named_values.len()) { Ok(ser) => ser, Err(e) => { *self = Self::End(Err(e)); return; } }; for (i, (_, v)) in named_values.iter().enumerate() { if let Err(e) = ser.serialize_field(fields[i].name(), &Serializable(v)) { *self = Self::End(Err(e)); return; } } *self = Self::End(ser.end()); } fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) { let (name, serializer) = match mem::replace(self, Self::Tmp) { Self::Start { name, fields: Fields::Unnamed(_), serializer, } => (name, serializer), mut res @ Self::End(..) => { if matches!(res, Self::End(Ok(..))) { res = Self::End(Err(S::Error::custom( "visit_unnamed_fields called multiple times in static struct", ))); } *self = res; return; } _ => unreachable!(), }; if values.len() == 1 { *self = Self::End(serializer.serialize_newtype_struct(name, &Serializable(values[0]))); return; } let mut ser = match serializer.serialize_tuple_struct(name, values.len()) { Ok(ser) => ser, Err(e) => { *self = Self::End(Err(e)); return; } }; for v in values { if let Err(e) = ser.serialize_field(&Serializable(v)) { *self = Self::End(Err(e)); return; } } *self = Self::End(ser.end()); } fn visit_entry(&mut self, _: Value<'_>, _: Value<'_>) { if !matches!(self, Self::End(Err(..))) { *self = Self::End(Err(S::Error::custom("visit_entry in struct"))); } } fn visit_value(&mut self, _: Value<'_>) { if !matches!(self, Self::End(Err(..))) { *self = Self::End(Err(S::Error::custom("visit_value in struct"))); } } } enum VisitStaticEnum { Start { name: &'static str, def: &'static [VariantDef<'static>], variant: &'static VariantDef<'static>, serializer: S, }, End(Result), Tmp, } impl Visit for VisitStaticEnum { fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) { let (name, def, variant, serializer) = match mem::replace(self, Self::Tmp) { Self::Start { name, def, variant, serializer, } => (name, def, variant, serializer), mut res @ Self::End(..) => { if matches!(res, Self::End(Ok(..))) { res = Self::End(Err(S::Error::custom( "visit_named_fields called multiple times in static enum", ))); } *self = res; return; } _ => unreachable!(), }; let variant_name = variant.name(); let variant_index = def.iter().position(|v| v.name() == variant_name).unwrap(); assert!(variant_index <= u32::MAX as usize); let mut ser = match serializer.serialize_struct_variant( name, variant_index as _, variant_name, named_values.len(), ) { Ok(ser) => ser, Err(e) => { *self = Self::End(Err(e)); return; } }; let fields = match variant.fields() { Fields::Named(fields) => fields, Fields::Unnamed(_) => unreachable!(), }; for (i, (_, v)) in named_values.iter().enumerate() { if let Err(e) = ser.serialize_field(fields[i].name(), &Serializable(v)) { *self = Self::End(Err(e)); return; } } *self = Self::End(ser.end()); } fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) { let (name, def, variant, serializer) = match mem::replace(self, Self::Tmp) { Self::Start { name, def, variant, serializer, } => (name, def, variant, serializer), mut res @ Self::End(..) => { if matches!(res, Self::End(Ok(..))) { res = Self::End(Err(S::Error::custom( "visit_unnamed_fields called multiple times in static enum", ))); } *self = res; return; } _ => unreachable!(), }; let variant_name = variant.name(); let variant_index = def.iter().position(|v| v.name() == variant_name).unwrap(); assert!(variant_index <= u32::MAX as usize); if values.len() == 1 { *self = Self::End(serializer.serialize_newtype_variant( name, variant_index as _, variant_name, &Serializable(values[0]), )); return; } let mut ser = match serializer.serialize_tuple_variant( name, variant_index as _, variant_name, values.len(), ) { Ok(ser) => ser, Err(e) => { *self = Self::End(Err(e)); return; } }; for v in values { if let Err(e) = ser.serialize_field(&Serializable(v)) { *self = Self::End(Err(e)); return; } } *self = Self::End(ser.end()); } fn visit_entry(&mut self, _: Value<'_>, _: Value<'_>) { if !matches!(self, Self::End(Err(..))) { *self = Self::End(Err(S::Error::custom("visit_entry in enum"))); } } fn visit_value(&mut self, _: Value<'_>) { if !matches!(self, Self::End(Err(..))) { *self = Self::End(Err(S::Error::custom("visit_value in enum"))); } } } enum VisitStaticTuple { Start(S::SerializeTuple), End(Result), Tmp, } impl Visit for VisitStaticTuple { fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) { let mut ser = match mem::replace(self, Self::Tmp) { Self::Start(ser) => ser, mut res @ Self::End(..) => { if matches!(res, Self::End(Ok(..))) { res = Self::End(Err(S::Error::custom( "visit_unnamed_fields called multiple times in static tuple", ))); } *self = res; return; } _ => unreachable!(), }; for v in values { if let Err(e) = ser.serialize_element(&Serializable(v)) { *self = Self::End(Err(e)); return; } } *self = Self::End(ser.end()); } fn visit_named_fields(&mut self, _: &NamedValues<'_>) { if !matches!(self, Self::End(Err(..))) { *self = Self::End(Err(S::Error::custom("visit_named_fields in tuple"))); } } fn visit_entry(&mut self, _: Value<'_>, _: Value<'_>) { if !matches!(self, Self::End(Err(..))) { *self = Self::End(Err(S::Error::custom("visit_entry in tuple"))); } } fn visit_value(&mut self, _: Value<'_>) { if !matches!(self, Self::End(Err(..))) { *self = Self::End(Err(S::Error::custom("visit_value in tuple"))); } } } // Dynamic struct, variant of dynamic enum, and dynamic tuple will be serialized as map or sequence. enum VisitDynamic<'a, S: Serializer> { // `Structable` or `Enumerable` with named fields. // Serialized as map. NamedFields(&'a mut S::SerializeMap), // `Structable` or `Enumerable` with unnamed fields, or `Tuplable`. // Serialized as sequence. UnnamedFields(&'a mut S::SerializeSeq), Error(S::Error), } impl Visit for VisitDynamic<'_, S> { fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) { let ser = match self { Self::NamedFields(ser) => ser, Self::Error(..) => return, Self::UnnamedFields(..) => { *self = Self::Error(S::Error::custom( "visit_named_fields in unnamed dynamic struct/variant", )); return; } }; for (f, v) in named_values { if let Err(e) = ser.serialize_entry(f.name(), &Serializable(v)) { *self = Self::Error(e); return; } } } fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) { let ser = match self { Self::UnnamedFields(ser) => ser, Self::Error(..) => return, Self::NamedFields(..) => { *self = Self::Error(S::Error::custom( "visit_unnamed_fields in named dynamic struct/variant", )); return; } }; for v in values { if let Err(e) = ser.serialize_element(&Serializable(v)) { *self = Self::Error(e); return; } } } fn visit_entry(&mut self, _: Value<'_>, _: Value<'_>) { if !matches!(self, Self::Error(..)) { *self = Self::Error(S::Error::custom("visit_entry in dynamic struct/variant")); } } fn visit_value(&mut self, _: Value<'_>) { if !matches!(self, Self::Error(..)) { *self = Self::Error(S::Error::custom("visit_value in dynamic struct/variant")); } } } valuable-serde-0.1.0/tests/test.rs000064400000000000000000000303560072674642500152430ustar 00000000000000use std::collections::BTreeMap; use serde::Serialize; use serde_test::{assert_ser_tokens, Token}; use valuable::*; use valuable_serde::Serializable; macro_rules! assert_ser_eq { ($value:expr, &[$($tokens:tt)*] $(,)?) => {{ let value = &$value; assert_ser_tokens(&Serializable::new(value), &[$($tokens)*]); assert_ser_tokens(value, &[$($tokens)*]); }}; } #[test] fn test_bool() { assert_ser_eq!(false, &[Token::Bool(false)]); assert_ser_eq!(true, &[Token::Bool(true)]); } #[test] fn test_int() { assert_ser_eq!(i8::MIN, &[Token::I8(i8::MIN)]); assert_ser_eq!(i8::MAX, &[Token::I8(i8::MAX)]); assert_ser_eq!(i16::MIN, &[Token::I16(i16::MIN)]); assert_ser_eq!(i16::MAX, &[Token::I16(i16::MAX)]); assert_ser_eq!(i32::MIN, &[Token::I32(i32::MIN)]); assert_ser_eq!(i32::MAX, &[Token::I32(i32::MAX)]); assert_ser_eq!(i64::MIN, &[Token::I64(i64::MIN)]); assert_ser_eq!(i64::MAX, &[Token::I64(i64::MAX)]); // serde_test doesn't have Token::I128. // assert_ser_eq!(i128::MIN, &[Token::I128(i128::MIN)]); // assert_ser_eq!(i128::MAX, &[Token::I128(i128::MAX)]); assert_ser_eq!(isize::MIN, &[Token::I64(isize::MIN as _)]); assert_ser_eq!(isize::MAX, &[Token::I64(isize::MAX as _)]); assert_ser_eq!(u8::MAX, &[Token::U8(u8::MAX)]); assert_ser_eq!(u16::MAX, &[Token::U16(u16::MAX)]); assert_ser_eq!(u32::MAX, &[Token::U32(u32::MAX)]); assert_ser_eq!(u64::MAX, &[Token::U64(u64::MAX)]); // serde_test doesn't have Token::U128. // assert_ser_eq!(u128::MAX, &[Token::U128(u128::MAX)]); assert_ser_eq!(usize::MAX, &[Token::U64(usize::MAX as _)]); } #[test] fn test_float() { assert_ser_eq!(f32::MIN, &[Token::F32(f32::MIN)]); assert_ser_eq!(f32::MAX, &[Token::F32(f32::MAX)]); assert_ser_eq!(f64::MIN, &[Token::F64(f64::MIN)]); assert_ser_eq!(f64::MAX, &[Token::F64(f64::MAX)]); } #[test] fn test_char() { assert_ser_eq!('a', &[Token::Char('a')]); } #[test] fn test_str() { assert_ser_eq!("a", &[Token::Str("a")]); assert_ser_eq!("a", &[Token::BorrowedStr("a")]); assert_ser_eq!("a", &[Token::String("a")]); assert_ser_eq!("a".to_string(), &[Token::Str("a")]); assert_ser_eq!("a".to_string(), &[Token::BorrowedStr("a")]); assert_ser_eq!("a".to_string(), &[Token::String("a")]); } // TODO: // - valuable treats Option as T or unit // - serde treats Option as Some(T) or None #[test] fn test_option() { assert_ser_tokens(&Serializable::new(None::), &[Token::Unit]); assert_ser_tokens(&None::, &[Token::None]); assert_ser_tokens(&Serializable::new(Some(1)), &[Token::I32(1)]); assert_ser_tokens(&Some(1), &[Token::Some, Token::I32(1)]); } #[test] fn test_unit() { assert_ser_eq!((), &[Token::Unit]); } // TODO: // - valuable treats unit struct as an empty tuple struct // - serde treats unit struct as unit struct #[test] fn test_unit_struct() { #[derive(Debug, PartialEq, Valuable, Serialize)] struct S; assert_ser_tokens( &Serializable::new(S), &[ Token::TupleStruct { name: "S", len: 0 }, Token::TupleStructEnd, ], ); assert_ser_tokens(&S, &[Token::UnitStruct { name: "S" }]); } // TODO: // - valuable treats unit variant as an empty tuple variant // - serde treats unit variant as unit variant #[test] fn test_unit_variant() { #[derive(Debug, PartialEq, Valuable, Serialize)] enum E { V, } assert_ser_tokens( &Serializable::new(E::V), &[ Token::TupleVariant { name: "E", variant: "V", len: 0, }, Token::TupleVariantEnd, ], ); assert_ser_tokens( &E::V, &[Token::UnitVariant { name: "E", variant: "V", }], ); } #[test] fn test_newtype_struct() { #[derive(Debug, PartialEq, Valuable, Serialize)] struct S(u8); assert_ser_eq!(S(0), &[Token::NewtypeStruct { name: "S" }, Token::U8(0)]); } #[test] fn test_newtype_variant() { #[derive(Debug, PartialEq, Valuable, Serialize)] enum E { V(u8), } assert_ser_eq!( E::V(0), &[ Token::NewtypeVariant { name: "E", variant: "V" }, Token::U8(0) ] ); } #[test] fn test_seq() { assert_ser_eq!( vec![1, 2, 3], &[ Token::Seq { len: Some(3) }, Token::I32(1), Token::I32(2), Token::I32(3), Token::SeqEnd ] ); } #[test] fn test_tuple() { assert_ser_eq!( (1,), &[Token::Tuple { len: 1 }, Token::I32(1), Token::TupleEnd] ); assert_ser_eq!( ("a", 'b'), &[ Token::Tuple { len: 2 }, Token::Str("a"), Token::Char('b'), Token::TupleEnd ] ); } #[test] fn test_tuple_struct() { #[derive(Debug, PartialEq, Valuable, Serialize)] struct S1(); #[derive(Debug, PartialEq, Valuable, Serialize)] struct S2(i8, u8); assert_ser_eq!( S1(), &[ Token::TupleStruct { name: "S1", len: 0 }, Token::TupleStructEnd ] ); assert_ser_eq!( S2(-1, 1), &[ Token::TupleStruct { name: "S2", len: 2 }, Token::I8(-1), Token::U8(1), Token::TupleStructEnd ] ); } #[test] fn test_tuple_variant() { #[derive(Debug, PartialEq, Valuable, Serialize)] enum E { V1(), V2(i8, u8), } assert_ser_eq!( E::V1(), &[ Token::TupleVariant { name: "E", variant: "V1", len: 0 }, Token::TupleVariantEnd ] ); assert_ser_eq!( E::V2(-1, 1), &[ Token::TupleVariant { name: "E", variant: "V2", len: 2 }, Token::I8(-1), Token::U8(1), Token::TupleVariantEnd ] ); } #[test] fn test_map() { let mut m = BTreeMap::new(); assert_ser_eq!(m, &[Token::Map { len: Some(0) }, Token::MapEnd]); m.insert(1, 10); m.insert(2, 20); assert_ser_eq!( m, &[ Token::Map { len: Some(2) }, Token::I32(1), Token::I32(10), Token::I32(2), Token::I32(20), Token::MapEnd ] ); } #[test] fn test_struct() { #[derive(Debug, PartialEq, Valuable, Serialize)] struct S1 {} #[derive(Debug, PartialEq, Valuable, Serialize)] struct S2 { f: u8, } assert_ser_eq!( S1 {}, &[Token::Struct { name: "S1", len: 0 }, Token::StructEnd] ); assert_ser_eq!( S2 { f: 1 }, &[ Token::Struct { name: "S2", len: 1 }, Token::Str("f"), Token::U8(1), Token::StructEnd ] ); } #[test] fn test_struct_variant() { #[derive(Debug, PartialEq, Valuable, Serialize)] enum E { V1 {}, V2 { f: u8 }, } assert_ser_eq!( E::V1 {}, &[ Token::StructVariant { name: "E", variant: "V1", len: 0 }, Token::StructVariantEnd ] ); assert_ser_eq!( E::V2 { f: 1 }, &[ Token::StructVariant { name: "E", variant: "V2", len: 1 }, Token::Str("f"), Token::U8(1), Token::StructVariantEnd ] ); } #[test] fn test_enum() { #[derive(Debug, PartialEq, Valuable, Serialize)] enum E { Unit, Newtype(u8), Tuple(u8, u8), Struct { f: u8 }, } // TODO: // - valuable treats unit variant as an empty tuple variant // - serde treats unit variant as unit variant assert_ser_tokens( &Serializable::new(E::Unit), &[ Token::Enum { name: "E" }, Token::Str("Unit"), Token::Seq { len: Some(0) }, Token::SeqEnd, ], ); assert_ser_tokens( &E::Unit, &[Token::Enum { name: "E" }, Token::Str("Unit"), Token::Unit], ); assert_ser_eq!( E::Newtype(0), &[ Token::Enum { name: "E" }, Token::Str("Newtype"), Token::U8(0), ], ); assert_ser_eq!( E::Tuple(0, 0), &[ Token::Enum { name: "E" }, Token::Str("Tuple"), Token::Seq { len: Some(2) }, Token::U8(0), Token::U8(0), Token::SeqEnd, ], ); assert_ser_eq!( E::Struct { f: 0 }, &[ Token::Enum { name: "E" }, Token::Str("Struct"), Token::Map { len: Some(1) }, Token::Str("f"), Token::U8(0), Token::MapEnd, ], ); } #[test] fn test_dyn_struct() { struct Named; impl Valuable for Named { fn as_value(&self) -> Value<'_> { Value::Structable(self) } fn visit(&self, visit: &mut dyn Visit) { visit.visit_named_fields(&NamedValues::new(&[NamedField::new("a")], &[Value::U32(1)])); visit.visit_named_fields(&NamedValues::new( &[NamedField::new("b")], &[Value::I32(-1)], )); } } impl Structable for Named { fn definition(&self) -> StructDef<'_> { StructDef::new_dynamic("Named", Fields::Named(&[])) } } struct Unnamed; impl Valuable for Unnamed { fn as_value(&self) -> Value<'_> { Value::Structable(self) } fn visit(&self, visit: &mut dyn Visit) { visit.visit_unnamed_fields(&[Value::U32(1)]); visit.visit_unnamed_fields(&[Value::I32(-1)]); } } impl Structable for Unnamed { fn definition(&self) -> StructDef<'_> { StructDef::new_dynamic("Unnamed", Fields::Unnamed(2)) } } assert_ser_tokens( &Serializable::new(Named), &[ Token::Map { len: None }, Token::Str("a"), Token::U32(1), Token::Str("b"), Token::I32(-1), Token::MapEnd, ], ); assert_ser_tokens( &Serializable::new(Unnamed), &[ Token::Seq { len: None }, Token::U32(1), Token::I32(-1), Token::SeqEnd, ], ); } #[test] fn test_dyn_enum() { enum E { Named, Unnamed, } impl Valuable for E { fn as_value(&self) -> Value<'_> { Value::Enumerable(self) } fn visit(&self, visit: &mut dyn Visit) { match self { Self::Named => { visit.visit_named_fields(&NamedValues::new( &[NamedField::new("a")], &[Value::U32(1)], )); visit.visit_named_fields(&NamedValues::new( &[NamedField::new("b")], &[Value::I32(-1)], )); } Self::Unnamed => { visit.visit_unnamed_fields(&[Value::U32(1)]); visit.visit_unnamed_fields(&[Value::I32(-1)]); } } } } impl Enumerable for E { fn definition(&self) -> EnumDef<'_> { EnumDef::new_dynamic("E", &[]) } fn variant(&self) -> Variant<'_> { match self { Self::Named => Variant::Dynamic(VariantDef::new("Named", Fields::Named(&[]))), Self::Unnamed => Variant::Dynamic(VariantDef::new("Named", Fields::Unnamed(2))), } } } assert_ser_tokens( &Serializable::new(E::Named), &[ Token::Map { len: None }, Token::Str("a"), Token::U32(1), Token::Str("b"), Token::I32(-1), Token::MapEnd, ], ); assert_ser_tokens( &Serializable::new(E::Unnamed), &[ Token::Seq { len: None }, Token::U32(1), Token::I32(-1), Token::SeqEnd, ], ); }