Skip to content

Commit

Permalink
Draft braced structs extension, no tests or special errors yet
Browse files Browse the repository at this point in the history
  • Loading branch information
juntyr committed Nov 2, 2024
1 parent ea6b406 commit 0a0672d
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 34 deletions.
64 changes: 54 additions & 10 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)?;
}
Expand Down Expand Up @@ -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 => ']',
}
Expand Down Expand Up @@ -856,7 +900,7 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
std::any::type_name::<K::Value>() == 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 =>
Expand Down
1 change: 1 addition & 0 deletions src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 14 additions & 2 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -668,7 +678,9 @@ impl<'a> Parser<'a> {

pub fn consume_struct_name(&mut self, ident: &'static str) -> Result<bool> {
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()));
}

Expand Down
64 changes: 42 additions & 22 deletions src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -956,25 +956,28 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer<W> {
self.start_indent()?;
}

Ok(Compound::new(self, false))
Ok(Compound::new(self, Some(']')))
}

fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
let old_newtype_variant = self.newtype_variant;
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);

self.start_indent()?;
}

Ok(Compound::new(self, old_newtype_variant))
Ok(Compound::new(self, closing))
}

fn serialize_tuple_struct(
Expand Down Expand Up @@ -1011,7 +1014,7 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer<W> {
self.start_indent()?;
}

Ok(Compound::new(self, false))
Ok(Compound::new(self, Some(')')))
}

fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
Expand All @@ -1028,31 +1031,37 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer<W> {
self.start_indent()?;
}

Ok(Compound::new(self, false))
Ok(Compound::new(self, Some('}')))
}

fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
let old_newtype_variant = self.newtype_variant;
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)?;
} else {
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(
Expand All @@ -1067,14 +1076,21 @@ impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer<W> {

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)))
}
}

Expand All @@ -1087,16 +1103,16 @@ enum State {
pub struct Compound<'a, W: fmt::Write> {
ser: &'a mut Serializer<W>,
state: State,
newtype_variant: bool,
closing: Option<char>,
sequence_index: usize,
}

impl<'a, W: fmt::Write> Compound<'a, W> {
fn new(ser: &'a mut Serializer<W>, newtype_variant: bool) -> Self {
fn new(ser: &'a mut Serializer<W>, closing: Option<char>) -> Self {
Compound {
ser,
state: State::First,
newtype_variant,
closing,
sequence_index: 0,
}
}
Expand Down Expand Up @@ -1161,8 +1177,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(())
}
}
Expand Down Expand Up @@ -1210,8 +1228,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(())
Expand Down Expand Up @@ -1309,8 +1327,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(())
}
}
Expand Down Expand Up @@ -1399,8 +1419,8 @@ 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(())
Expand Down

0 comments on commit 0a0672d

Please sign in to comment.