From 4711cdb18df008c524ed2c03535297fe1a84f533 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 7 Sep 2023 20:48:41 -0500 Subject: [PATCH] fix(serde): Bubble up nested None errors Fixes #603 --- crates/toml/tests/testsuite/serde.rs | 5 +- crates/toml_edit/src/ser/map.rs | 192 ++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 8 deletions(-) diff --git a/crates/toml/tests/testsuite/serde.rs b/crates/toml/tests/testsuite/serde.rs index cfe0fabd..1d2fe4f0 100644 --- a/crates/toml/tests/testsuite/serde.rs +++ b/crates/toml/tests/testsuite/serde.rs @@ -1112,7 +1112,6 @@ fn serialize_array_with_none_value() { let input = Document { values: vec![Some(1), None, Some(3)], }; - let expected = ""; - let raw = toml::to_string(&input).unwrap(); - snapbox::assert_eq(expected, raw); + let err = toml::to_string(&input).unwrap_err(); + snapbox::assert_eq("unsupported None value", err.to_string()); } diff --git a/crates/toml_edit/src/ser/map.rs b/crates/toml_edit/src/ser/map.rs index d743e3d5..951a5cb9 100644 --- a/crates/toml_edit/src/ser/map.rs +++ b/crates/toml_edit/src/ser/map.rs @@ -1,4 +1,4 @@ -use super::{Error, KeySerializer}; +use super::{Error, KeySerializer, ValueSerializer}; #[doc(hidden)] pub enum SerializeMap { @@ -174,7 +174,8 @@ impl serde::ser::SerializeMap for SerializeInlineTable { where T: serde::ser::Serialize, { - let res = value.serialize(super::ValueSerializer {}); + let mut value_serializer = MapValueSerializer::new(); + let res = value.serialize(&mut value_serializer); match res { Ok(item) => { let key = self.key.take().unwrap(); @@ -185,7 +186,7 @@ impl serde::ser::SerializeMap for SerializeInlineTable { self.items.insert(key, kv); } Err(e) => { - if e != Error::UnsupportedNone { + if !(e == Error::UnsupportedNone && value_serializer.is_none) { return Err(e); } } @@ -210,7 +211,8 @@ impl serde::ser::SerializeStruct for SerializeInlineTable { where T: serde::ser::Serialize, { - let res = value.serialize(super::ValueSerializer {}); + let mut value_serializer = MapValueSerializer::new(); + let res = value.serialize(&mut value_serializer); match res { Ok(item) => { let kv = crate::table::TableKeyValue::new( @@ -220,7 +222,7 @@ impl serde::ser::SerializeStruct for SerializeInlineTable { self.items.insert(crate::InternalString::from(key), kv); } Err(e) => { - if e != Error::UnsupportedNone { + if !(e == Error::UnsupportedNone && value_serializer.is_none) { return Err(e); } } @@ -403,3 +405,183 @@ impl serde::ser::Serializer for DatetimeFieldSerializer { Err(Error::DateInvalid) } } + +#[derive(Default)] +struct MapValueSerializer { + is_none: bool, +} + +impl MapValueSerializer { + fn new() -> Self { + Self { is_none: false } + } +} + +impl serde::ser::Serializer for &mut MapValueSerializer { + type Ok = crate::Value; + type Error = Error; + type SerializeSeq = super::SerializeValueArray; + type SerializeTuple = super::SerializeValueArray; + type SerializeTupleStruct = super::SerializeValueArray; + type SerializeTupleVariant = super::SerializeValueArray; + type SerializeMap = super::SerializeMap; + type SerializeStruct = super::SerializeMap; + type SerializeStructVariant = serde::ser::Impossible; + + fn serialize_bool(self, v: bool) -> Result { + ValueSerializer::new().serialize_bool(v) + } + + fn serialize_i8(self, v: i8) -> Result { + ValueSerializer::new().serialize_i8(v) + } + + fn serialize_i16(self, v: i16) -> Result { + ValueSerializer::new().serialize_i16(v) + } + + fn serialize_i32(self, v: i32) -> Result { + ValueSerializer::new().serialize_i32(v) + } + + fn serialize_i64(self, v: i64) -> Result { + ValueSerializer::new().serialize_i64(v) + } + + fn serialize_u8(self, v: u8) -> Result { + ValueSerializer::new().serialize_u8(v) + } + + fn serialize_u16(self, v: u16) -> Result { + ValueSerializer::new().serialize_u16(v) + } + + fn serialize_u32(self, v: u32) -> Result { + ValueSerializer::new().serialize_u32(v) + } + + fn serialize_u64(self, v: u64) -> Result { + ValueSerializer::new().serialize_u64(v) + } + + fn serialize_f32(self, v: f32) -> Result { + ValueSerializer::new().serialize_f32(v) + } + + fn serialize_f64(self, v: f64) -> Result { + ValueSerializer::new().serialize_f64(v) + } + + fn serialize_char(self, v: char) -> Result { + ValueSerializer::new().serialize_char(v) + } + + fn serialize_str(self, v: &str) -> Result { + ValueSerializer::new().serialize_str(v) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + ValueSerializer::new().serialize_bytes(value) + } + + fn serialize_none(self) -> Result { + self.is_none = true; + Err(Error::UnsupportedNone) + } + + fn serialize_some(self, value: &T) -> Result + where + T: serde::ser::Serialize, + { + ValueSerializer::new().serialize_some(value) + } + + fn serialize_unit(self) -> Result { + ValueSerializer::new().serialize_unit() + } + + fn serialize_unit_struct(self, name: &'static str) -> Result { + ValueSerializer::new().serialize_unit_struct(name) + } + + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result { + ValueSerializer::new().serialize_unit_variant(name, variant_index, variant) + } + + fn serialize_newtype_struct( + self, + name: &'static str, + value: &T, + ) -> Result + where + T: serde::ser::Serialize, + { + ValueSerializer::new().serialize_newtype_struct(name, value) + } + + fn serialize_newtype_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: serde::ser::Serialize, + { + ValueSerializer::new().serialize_newtype_variant(name, variant_index, variant, value) + } + + fn serialize_seq(self, len: Option) -> Result { + ValueSerializer::new().serialize_seq(len) + } + + fn serialize_tuple(self, len: usize) -> Result { + ValueSerializer::new().serialize_tuple(len) + } + + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + ValueSerializer::new().serialize_tuple_struct(name, len) + } + + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + ValueSerializer::new().serialize_tuple_variant(name, variant_index, variant, len) + } + + fn serialize_map(self, len: Option) -> Result { + ValueSerializer::new().serialize_map(len) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + ValueSerializer::new().serialize_struct(name, len) + } + + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + ValueSerializer::new().serialize_struct_variant(name, variant_index, variant, len) + } +}