diff --git a/src/ser.rs b/src/ser.rs index 2111efd..7ab1d77 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -14,6 +14,7 @@ use crate::writer::{self, Writer}; pub struct Serializer<'config, Output> { writer: Writer<'config, Output>, implicit_map_at_root: bool, + anonymous_structs: bool, } impl Default for Serializer<'static, String> { @@ -21,6 +22,7 @@ impl Default for Serializer<'static, String> { Self { writer: Writer::default(), implicit_map_at_root: false, + anonymous_structs: false, } } } @@ -33,6 +35,7 @@ where Self { writer: Writer::new(output, &config.writer), implicit_map_at_root: config.implicit_map_at_root, + anonymous_structs: config.anonymous_structs, } } @@ -239,6 +242,7 @@ where Ok(self) } + // TODO implicit_map_at_root fn serialize_map(self, _len: Option) -> Result { self.mark_value_seen(); self.writer.begin_map()?; @@ -254,7 +258,11 @@ where self.mark_value_seen(); if !is_implicit_map { - self.writer.begin_named_map(name)?; + if self.anonymous_structs { + self.writer.begin_map()?; + } else { + self.writer.begin_named_map(name)?; + } } Ok(StructSerializer { @@ -438,16 +446,21 @@ where pub struct Config { pub writer: writer::Config, pub implicit_map_at_root: bool, + pub anonymous_structs: bool, } impl Config { + pub fn new() -> Self { + Self::default() + } + pub fn pretty() -> Self { Self { writer: writer::Config::Pretty { indentation: Cow::Borrowed(" "), newline: Cow::Borrowed("\n"), }, - implicit_map_at_root: false, + ..Default::default() } } @@ -456,6 +469,11 @@ impl Config { self } + pub const fn anonymous_structs(mut self, anonymous_structs: bool) -> Self { + self.anonymous_structs = anonymous_structs; + self + } + pub fn serialize(&self, value: &S) -> String { let mut serializer = Serializer::new(String::new(), self); value.serialize(&mut serializer).expect("core::fmt::Error"); diff --git a/src/tests/serde.rs b/src/tests/serde.rs index 6731882..c5eaa76 100644 --- a/src/tests/serde.rs +++ b/src/tests/serde.rs @@ -108,6 +108,23 @@ fn roundtrip_implicit_map Deserialize<'de> + Par assert_eq!(&restored, value); } +#[track_caller] +fn roundtrip_anonymous_structs Deserialize<'de> + PartialEq>( + value: &T, + check: &str, +) { + let rendered = crate::ser::Config::new() + .anonymous_structs(true) + .serialize(value); + println!("{rendered}"); + assert_eq!(rendered, check); + let restored: T = crate::parser::Config::default() + .allow_implicit_map(true) + .deserialize(&rendered) + .expect("deserialization failed"); + assert_eq!(&restored, value); +} + #[test] fn struct_of_everything() { roundtrip(&StructOfEverything::default(), "StructOfEverything{str:\"\",bytes:b\"\",char:'\\0',u8:0,u16:0,u32:0,u64:0,u128:0,usize:0,i8:0,i16:0,i32:0,i64:0,i128:0,isize:0,bool:false}"); @@ -129,6 +146,13 @@ fn struct_of_everything_implicit() { roundtrip_implicit_map(&StructOfEverything::max(), "str: \"hello 🦀\"\nbytes: b\"hello, world\"\nchar: '🦀'\nu8: 255\nu16: 65535\nu32: 4294967295\nu64: 18446744073709551615\nu128: 18446744073709551615\nusize: 18446744073709551615\ni8: 127\ni16: 32767\ni32: 2147483647\ni64: 9223372036854775807\ni128: 9223372036854775807\nisize: 9223372036854775807\nbool: true\n"); } +#[test] +fn struct_of_everything_anonymous() { + roundtrip_anonymous_structs(&StructOfEverything::default(), "{str:\"\",bytes:b\"\",char:'\\0',u8:0,u16:0,u32:0,u64:0,u128:0,usize:0,i8:0,i16:0,i32:0,i64:0,i128:0,isize:0,bool:false}"); + roundtrip_anonymous_structs(&StructOfEverything::min(), "{str:\"\\0\",bytes:b\"\\0\",char:'\\0',u8:0,u16:0,u32:0,u64:0,u128:0,usize:0,i8:-128,i16:-32768,i32:-2147483648,i64:-9223372036854775808,i128:-9223372036854775808,isize:-9223372036854775808,bool:false}"); + roundtrip_anonymous_structs(&StructOfEverything::max(), "{str:\"hello 🦀\",bytes:b\"hello, world\",char:'🦀',u8:255,u16:65535,u32:4294967295,u64:18446744073709551615,u128:18446744073709551615,usize:18446744073709551615,i8:127,i16:32767,i32:2147483647,i64:9223372036854775807,i128:9223372036854775807,isize:9223372036854775807,bool:true}"); +} + #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] #[serde(untagged)] enum UntaggedEnum {