From 6ca8c1de451b26d4bb6c5b8d0916a8dec4dd65f0 Mon Sep 17 00:00:00 2001 From: Juniper Tyree <50025784+juntyr@users.noreply.github.com> Date: Sat, 2 Nov 2024 05:48:05 +0000 Subject: [PATCH] Draft braced structs extension, no tests or special errors yet --- src/de/mod.rs | 64 ++++++++++++++++++++++++++++++++++++++-------- src/extensions.rs | 1 + src/parse.rs | 16 ++++++++++-- src/ser/mod.rs | 65 +++++++++++++++++++++++++++++++---------------- 4 files changed, 112 insertions(+), 34 deletions(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index 6028236b6..9fcc22695 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -176,6 +176,21 @@ impl<'de> Deserializer<'de> { let old_serde_content_newtype = self.serde_content_newtype; self.serde_content_newtype = false; + if let Some(ident) = ident { + if is_serde_content { + // serde's Content type uses a singleton map encoding for enums + return visitor.visit_map(SerdeEnumContent { + de: self, + ident: Some(ident), + }); + } + + if self.extensions().contains(Extensions::BRACED_STRUCTS) { + // giving no name results in worse errors but is necessary here + return self.handle_struct_after_name("", visitor); + } + } + match ( self.parser.check_struct_type( NewtypeMode::NoParensMeanUnit, @@ -192,13 +207,6 @@ impl<'de> Deserializer<'de> { visitor.visit_str(ident) } (StructType::Unit, _) => visitor.visit_unit(), - (_, Some(ident)) if is_serde_content => { - // serde's Content type uses a singleton map encoding for enums - visitor.visit_map(SerdeEnumContent { - de: self, - ident: Some(ident), - }) - } (StructType::Named, _) => { // giving no name results in worse errors but is necessary here self.handle_struct_after_name("", visitor) @@ -241,7 +249,38 @@ impl<'de> Deserializer<'de> { where V: Visitor<'de>, { - if self.newtype_variant || self.parser.consume_char('(') { + if self.extensions().contains(Extensions::BRACED_STRUCTS) { + self.newtype_variant = false; + + if self.parser.consume_char('{') { + let value = guard_recursion! { self => + visitor + .visit_map(CommaSeparated::new(Terminator::BracedStruct, self)) + .map_err(|err| { + struct_error_name( + err, + if !name_for_pretty_errors_only.is_empty() { + Some(name_for_pretty_errors_only) + } else { + None + }, + ) + })? + }; + + self.parser.skip_ws()?; + + if self.parser.consume_char('}') { + Ok(value) + } else { + Err(Error::ExpectedStructLikeEnd) + } + } else if name_for_pretty_errors_only.is_empty() { + Err(Error::ExpectedStructLike) + } else { + Err(Error::ExpectedNamedStructLike(name_for_pretty_errors_only)) + } + } else if self.newtype_variant || self.parser.consume_char('(') { let old_newtype_variant = self.newtype_variant; self.newtype_variant = false; @@ -719,6 +758,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { + if self.extensions().contains(Extensions::BRACED_STRUCTS) { + self.newtype_variant = false; + } + if !self.newtype_variant { self.parser.consume_struct_name(name)?; } @@ -778,13 +821,14 @@ enum Terminator { MapAsStruct, Tuple, Struct, + BracedStruct, Seq, } impl Terminator { fn as_char(&self) -> char { match self { - Terminator::Map | Terminator::MapAsStruct => '}', + Terminator::Map | Terminator::MapAsStruct | Terminator::BracedStruct => '}', Terminator::Tuple | Terminator::Struct => ')', Terminator::Seq => ']', } @@ -856,7 +900,7 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> { std::any::type_name::() == SERDE_TAG_KEY_CANARY; match self.terminator { - Terminator::Struct => guard_recursion! { self.de => + Terminator::Struct | Terminator::BracedStruct => guard_recursion! { self.de => seed.deserialize(&mut id::Deserializer::new(&mut *self.de, false)).map(Some) }, Terminator::MapAsStruct => guard_recursion! { self.de => diff --git a/src/extensions.rs b/src/extensions.rs index c4862b791..a37f07688 100644 --- a/src/extensions.rs +++ b/src/extensions.rs @@ -11,6 +11,7 @@ bitflags::bitflags! { /// /// During deserialization, this extension requires that structs' names are stated explicitly. const EXPLICIT_STRUCT_NAMES = 0x8; + const BRACED_STRUCTS = 0x10; } } // GRCOV_EXCL_STOP diff --git a/src/parse.rs b/src/parse.rs index b1d4f8831..f3553390d 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -572,7 +572,17 @@ impl<'a> Parser<'a> { match parser.peek_char() { // Definitely a struct with named fields - Some(':') => return Ok(StructType::Named), + Some(':') => { + if parser.exts.contains(Extensions::BRACED_STRUCTS) { + return Err(Error::ExpectedStructLike); + } else { + return Ok(StructType::Named); + } + } + // Definitely a braced struct with named fields + Some('{') if parser.exts.contains(Extensions::BRACED_STRUCTS) => { + return Ok(StructType::Named) + } // Definitely a tuple-like struct with fields Some(',') => { parser.skip_next_char(); @@ -668,7 +678,9 @@ impl<'a> Parser<'a> { pub fn consume_struct_name(&mut self, ident: &'static str) -> Result { if self.check_ident("") { - if self.exts.contains(Extensions::EXPLICIT_STRUCT_NAMES) { + if self.exts.contains(Extensions::EXPLICIT_STRUCT_NAMES) + || self.exts.contains(Extensions::BRACED_STRUCTS) + { return Err(Error::ExpectedStructName(ident.to_string())); } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 6157f05f1..28171d893 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -946,7 +946,7 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { self.start_indent()?; } - Ok(Compound::new(self, false)) + Ok(Compound::new(self, Some(']'))) } fn serialize_tuple(self, len: usize) -> Result { @@ -954,9 +954,12 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { self.newtype_variant = false; self.implicit_some_depth = 0; - if !old_newtype_variant { + let closing = if old_newtype_variant { + None + } else { self.output.write_char('(')?; - } + Some(')') + }; if self.separate_tuple_members() { self.is_empty = Some(len == 0); @@ -964,7 +967,7 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { self.start_indent()?; } - Ok(Compound::new(self, old_newtype_variant)) + Ok(Compound::new(self, closing)) } fn serialize_tuple_struct( @@ -1001,7 +1004,7 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { self.start_indent()?; } - Ok(Compound::new(self, false)) + Ok(Compound::new(self, Some(')'))) } fn serialize_map(self, len: Option) -> Result { @@ -1018,7 +1021,7 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { self.start_indent()?; } - Ok(Compound::new(self, false)) + Ok(Compound::new(self, Some('}'))) } fn serialize_struct(self, name: &'static str, len: usize) -> Result { @@ -1026,8 +1029,13 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { self.newtype_variant = false; self.implicit_some_depth = 0; - if old_newtype_variant { + let closing = if self.extensions().contains(Extensions::BRACED_STRUCTS) { + self.write_identifier(name)?; + self.output.write_char('{')?; + Some('}') + } else if old_newtype_variant { self.validate_identifier(name)?; + None } else { if self.struct_names() { self.write_identifier(name)?; @@ -1035,14 +1043,15 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { self.validate_identifier(name)?; } self.output.write_char('(')?; - } + Some(')') + }; if !self.compact_structs() { self.is_empty = Some(len == 0); self.start_indent()?; } - Ok(Compound::new(self, old_newtype_variant)) + Ok(Compound::new(self, closing)) } fn serialize_struct_variant( @@ -1057,14 +1066,21 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { self.validate_identifier(name)?; self.write_identifier(variant)?; - self.output.write_char('(')?; + + let closing = if self.extensions().contains(Extensions::BRACED_STRUCTS) { + self.output.write_char('{')?; + '}' + } else { + self.output.write_char('(')?; + ')' + }; if !self.compact_structs() { self.is_empty = Some(len == 0); self.start_indent()?; } - Ok(Compound::new(self, false)) + Ok(Compound::new(self, Some(closing))) } } @@ -1077,16 +1093,16 @@ enum State { pub struct Compound<'a, W: fmt::Write> { ser: &'a mut Serializer, state: State, - newtype_variant: bool, + closing: Option, sequence_index: usize, } impl<'a, W: fmt::Write> Compound<'a, W> { - fn new(ser: &'a mut Serializer, newtype_variant: bool) -> Self { + fn new(ser: &'a mut Serializer, closing: Option) -> Self { Compound { ser, state: State::First, - newtype_variant, + closing, sequence_index: 0, } } @@ -1151,8 +1167,10 @@ impl<'a, W: fmt::Write> ser::SerializeSeq for Compound<'a, W> { self.ser.end_indent()?; } - // seq always disables `self.newtype_variant` - self.ser.output.write_char(']')?; + if let Some(closing) = self.closing { + self.ser.output.write_char(closing)?; + } + Ok(()) } } @@ -1200,8 +1218,8 @@ impl<'a, W: fmt::Write> ser::SerializeTuple for Compound<'a, W> { self.ser.end_indent()?; } - if !self.newtype_variant { - self.ser.output.write_char(')')?; + if let Some(closing) = self.closing { + self.ser.output.write_char(closing)?; } Ok(()) @@ -1299,8 +1317,10 @@ impl<'a, W: fmt::Write> ser::SerializeMap for Compound<'a, W> { self.ser.end_indent()?; } - // map always disables `self.newtype_variant` - self.ser.output.write_char('}')?; + if let Some(closing) = self.closing { + self.ser.output.write_char(closing)?; + } + Ok(()) } } @@ -1357,9 +1377,10 @@ impl<'a, W: fmt::Write> ser::SerializeStruct for Compound<'a, W> { self.ser.end_indent()?; } - if !self.newtype_variant { - self.ser.output.write_char(')')?; + if let Some(closing) = self.closing { + self.ser.output.write_char(closing)?; } + Ok(()) } }