Skip to content

Commit

Permalink
Merge pull request #604 from epage/ser
Browse files Browse the repository at this point in the history
fix(serde): Bubble up nested None errors
  • Loading branch information
epage authored Sep 8, 2023
2 parents 954b65a + 4711cdb commit b47f77c
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 5 deletions.
21 changes: 21 additions & 0 deletions crates/toml/tests/testsuite/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1094,3 +1094,24 @@ fn datetime_offset_issue_496() {
let output = toml.to_string();
snapbox::assert_eq(original, output);
}

#[test]
fn serialize_array_with_none_value() {
#[derive(Serialize)]
struct Document {
values: Vec<Option<usize>>,
}

let input = Document {
values: vec![Some(1), Some(2), Some(3)],
};
let expected = "values = [1, 2, 3]\n";
let raw = toml::to_string(&input).unwrap();
snapbox::assert_eq(expected, raw);

let input = Document {
values: vec![Some(1), None, Some(3)],
};
let err = toml::to_string(&input).unwrap_err();
snapbox::assert_eq("unsupported None value", err.to_string());
}
192 changes: 187 additions & 5 deletions crates/toml_edit/src/ser/map.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Error, KeySerializer};
use super::{Error, KeySerializer, ValueSerializer};

#[doc(hidden)]
pub enum SerializeMap {
Expand Down Expand Up @@ -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();
Expand All @@ -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);
}
}
Expand All @@ -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(
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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<Self::Ok, Self::Error>;

fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_bool(v)
}

fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_i8(v)
}

fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_i16(v)
}

fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_i32(v)
}

fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_i64(v)
}

fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_u8(v)
}

fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_u16(v)
}

fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_u32(v)
}

fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_u64(v)
}

fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_f32(v)
}

fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_f64(v)
}

fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_char(v)
}

fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_str(v)
}

fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_bytes(value)
}

fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
self.is_none = true;
Err(Error::UnsupportedNone)
}

fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize,
{
ValueSerializer::new().serialize_some(value)
}

fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_unit()
}

fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_unit_struct(name)
}

fn serialize_unit_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_unit_variant(name, variant_index, variant)
}

fn serialize_newtype_struct<T: ?Sized>(
self,
name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize,
{
ValueSerializer::new().serialize_newtype_struct(name, value)
}

fn serialize_newtype_variant<T: ?Sized>(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize,
{
ValueSerializer::new().serialize_newtype_variant(name, variant_index, variant, value)
}

fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
ValueSerializer::new().serialize_seq(len)
}

fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
ValueSerializer::new().serialize_tuple(len)
}

fn serialize_tuple_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
ValueSerializer::new().serialize_tuple_struct(name, len)
}

fn serialize_tuple_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
ValueSerializer::new().serialize_tuple_variant(name, variant_index, variant, len)
}

fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
ValueSerializer::new().serialize_map(len)
}

fn serialize_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
ValueSerializer::new().serialize_struct(name, len)
}

fn serialize_struct_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
ValueSerializer::new().serialize_struct_variant(name, variant_index, variant, len)
}
}

0 comments on commit b47f77c

Please sign in to comment.