Skip to content

Commit

Permalink
fix(serde): Support struct variants as table of a table
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Sep 13, 2023
1 parent 88a4dba commit 58a7101
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 15 deletions.
46 changes: 41 additions & 5 deletions crates/toml/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ impl ser::Serializer for ValueSerializer {
type SerializeTupleVariant = ValueSerializeTupleVariant;
type SerializeMap = ValueSerializeMap;
type SerializeStruct = ValueSerializeMap;
type SerializeStructVariant = ser::Impossible<Value, crate::ser::Error>;
type SerializeStructVariant = ValueSerializeStructVariant;

fn serialize_bool(self, value: bool) -> Result<Value, crate::ser::Error> {
Ok(Value::Boolean(value))
Expand Down Expand Up @@ -1054,12 +1054,12 @@ impl ser::Serializer for ValueSerializer {

fn serialize_struct_variant(
self,
name: &'static str,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, crate::ser::Error> {
Err(crate::ser::Error::unsupported_type(Some(name)))
Ok(ValueSerializeStructVariant::struct_(variant, len))
}
}

Expand Down Expand Up @@ -1469,6 +1469,7 @@ impl<'a, 'de> de::Visitor<'de> for DatetimeOrTable<'a> {
}

type ValueSerializeTupleVariant = ValueSerializeVariant<ValueSerializeVec>;
type ValueSerializeStructVariant = ValueSerializeVariant<ValueSerializeMap>;

struct ValueSerializeVariant<T> {
variant: &'static str,
Expand All @@ -1486,6 +1487,20 @@ impl ValueSerializeVariant<ValueSerializeVec> {
}
}

impl ValueSerializeVariant<ValueSerializeMap> {
pub(crate) fn struct_(variant: &'static str, len: usize) -> Self {
Self {
variant,
inner: ValueSerializeMap {
ser: SerializeMap {
map: Table::with_capacity(len),
next_key: None,
},
},
}
}
}

impl serde::ser::SerializeTupleVariant for ValueSerializeVariant<ValueSerializeVec> {
type Ok = crate::Value;
type Error = crate::ser::Error;
Expand All @@ -1504,3 +1519,24 @@ impl serde::ser::SerializeTupleVariant for ValueSerializeVariant<ValueSerializeV
Ok(Value::Table(table))
}
}

impl serde::ser::SerializeStructVariant for ValueSerializeVariant<ValueSerializeMap> {
type Ok = crate::Value;
type Error = crate::ser::Error;

#[inline]
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
serde::ser::SerializeStruct::serialize_field(&mut self.inner, key, value)
}

#[inline]
fn end(self) -> Result<Self::Ok, Self::Error> {
let inner = serde::ser::SerializeStruct::end(self.inner)?;
let mut table = Table::new();
table.insert(self.variant.to_owned(), inner);
Ok(Value::Table(table))
}
}
19 changes: 15 additions & 4 deletions crates/toml/tests/testsuite/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,21 @@ fn parse_struct_variant() {
},
],
};
let err = toml::to_string(&input).unwrap_err();
snapbox::assert_eq("unsupported Enum type", err.to_string());
let expected = "[[inner]]
[inner.Int]
first = 1
second = 1
[[inner]]
[inner.String]
first = \"2\"
second = \"2\"
";
let raw = toml::to_string(&input).unwrap();
snapbox::assert_eq(expected, raw);

/*
equivalent! {
Document {
inner: vec![
Expand All @@ -469,7 +480,7 @@ fn parse_struct_variant() {
map! { String: map! { first: "2".to_owned(), second: "2".to_owned() } },
]
},
}*/
}
}

#[test]
Expand Down
39 changes: 38 additions & 1 deletion crates/toml_edit/src/ser/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ impl serde::ser::Serializer for &mut MapValueSerializer {
type SerializeTupleVariant = super::SerializeTupleVariant;
type SerializeMap = super::SerializeMap;
type SerializeStruct = super::SerializeMap;
type SerializeStructVariant = serde::ser::Impossible<Self::Ok, Self::Error>;
type SerializeStructVariant = super::SerializeStructVariant;

fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_bool(v)
Expand Down Expand Up @@ -586,6 +586,7 @@ impl serde::ser::Serializer for &mut MapValueSerializer {
}

pub type SerializeTupleVariant = SerializeVariant<SerializeValueArray>;
pub type SerializeStructVariant = SerializeVariant<SerializeMap>;

pub struct SerializeVariant<T> {
variant: &'static str,
Expand All @@ -601,6 +602,15 @@ impl SerializeVariant<SerializeValueArray> {
}
}

impl SerializeVariant<SerializeMap> {
pub(crate) fn struct_(variant: &'static str, len: usize) -> Self {
Self {
variant,
inner: SerializeMap::table_with_capacity(len),
}
}
}

impl serde::ser::SerializeTupleVariant for SerializeVariant<SerializeValueArray> {
type Ok = crate::Value;
type Error = Error;
Expand All @@ -625,3 +635,30 @@ impl serde::ser::SerializeTupleVariant for SerializeVariant<SerializeValueArray>
)))
}
}

impl serde::ser::SerializeStructVariant for SerializeVariant<SerializeMap> {
type Ok = crate::Value;
type Error = Error;

#[inline]
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
serde::ser::SerializeStruct::serialize_field(&mut self.inner, key, value)
}

#[inline]
fn end(self) -> Result<Self::Ok, Self::Error> {
let inner = serde::ser::SerializeStruct::end(self.inner)?;
let mut items = crate::table::KeyValuePairs::new();
let kv = crate::table::TableKeyValue::new(
crate::Key::new(self.variant),
crate::Item::Value(inner),
);
items.insert(crate::InternalString::from(self.variant), kv);
Ok(crate::Value::InlineTable(crate::InlineTable::with_pairs(
items,
)))
}
}
10 changes: 5 additions & 5 deletions crates/toml_edit/src/ser/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl serde::ser::Serializer for ValueSerializer {
type SerializeTupleVariant = super::SerializeTupleVariant;
type SerializeMap = super::SerializeMap;
type SerializeStruct = super::SerializeMap;
type SerializeStructVariant = serde::ser::Impossible<Self::Ok, Self::Error>;
type SerializeStructVariant = super::SerializeStructVariant;

fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
Ok(v.into())
Expand Down Expand Up @@ -233,11 +233,11 @@ impl serde::ser::Serializer for ValueSerializer {

fn serialize_struct_variant(
self,
name: &'static str,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Err(Error::UnsupportedType(Some(name)))
Ok(super::SerializeStructVariant::struct_(variant, len))
}
}

0 comments on commit 58a7101

Please sign in to comment.