diff --git a/src/serde/mod.rs b/src/serde/mod.rs index 09470389..c7b131b2 100644 --- a/src/serde/mod.rs +++ b/src/serde/mod.rs @@ -474,4 +474,119 @@ mod tests { assert_eq!(&from_ion::(s).unwrap(), &ip); assert_eq!(&from_ion::(binary).unwrap(), &ip); } + + /// Regression tests for annotations being correctly written for all value types + /// when serialized through newtype variants (which produce annotations in Ion). + mod newtype_variant_annotations { + use super::*; + use std::collections::BTreeMap; + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Wrapper { + Tag(bool), + Num(f32), + Big(f64), + Items(Vec), + Dict(BTreeMap), + Record { x: i32, y: i32 }, + Price(Decimal), + When(Timestamp), + } + + #[test] + fn newtype_variant_bool() { + let val = Wrapper::Tag(true); + let ion = to_string(&val).unwrap(); + assert_eq!(Element::read_first("Tag::true"), Element::read_first(&ion)); + let roundtrip: Wrapper = from_ion(&ion).unwrap(); + assert_eq!(val, roundtrip); + } + + #[test] + fn newtype_variant_f32() { + let val = Wrapper::Num(2.5f32); + let ion = to_string(&val).unwrap(); + assert_eq!(Element::read_first("Num::2.5e0"), Element::read_first(&ion)); + let roundtrip: Wrapper = from_ion(&ion).unwrap(); + assert_eq!(val, roundtrip); + } + + #[test] + fn newtype_variant_f64() { + let val = Wrapper::Big(1.234f64); + let ion = to_string(&val).unwrap(); + assert_eq!( + Element::read_first("Big::1.234e0"), + Element::read_first(&ion) + ); + let roundtrip: Wrapper = from_ion(&ion).unwrap(); + assert_eq!(val, roundtrip); + } + + #[test] + fn newtype_variant_seq() { + let val = Wrapper::Items(vec![1, 2, 3]); + let ion = to_string(&val).unwrap(); + assert_eq!( + Element::read_first("Items::[1, 2, 3]"), + Element::read_first(&ion) + ); + let roundtrip: Wrapper = from_ion(&ion).unwrap(); + assert_eq!(val, roundtrip); + } + + #[test] + fn newtype_variant_map() { + let mut map = BTreeMap::new(); + map.insert("a".to_string(), 1u32); + let val = Wrapper::Dict(map); + let ion = to_string(&val).unwrap(); + assert_eq!( + Element::read_first("Dict::{a: 1}"), + Element::read_first(&ion) + ); + let roundtrip: Wrapper = from_ion(&ion).unwrap(); + assert_eq!(val, roundtrip); + } + + #[test] + fn newtype_variant_struct() { + let val = Wrapper::Record { x: 10, y: 20 }; + let ion = to_string(&val).unwrap(); + assert_eq!( + Element::read_first("Record::{x: 10, y: 20}"), + Element::read_first(&ion) + ); + let roundtrip: Wrapper = from_ion(&ion).unwrap(); + assert_eq!(val, roundtrip); + } + + #[test] + fn newtype_variant_decimal() { + let val = Wrapper::Price(Decimal::new(199, -2)); + let ion = to_string(&val).unwrap(); + assert_eq!( + Element::read_first("Price::1.99"), + Element::read_first(&ion) + ); + let roundtrip: Wrapper = from_ion(&ion).unwrap(); + assert_eq!(val, roundtrip); + } + + #[test] + fn newtype_variant_timestamp() { + let ts = Timestamp::with_ymd(2024, 6, 15) + .with_hms(12, 0, 0) + .build() + .unwrap(); + let val = Wrapper::When(ts.clone()); + let ion = to_string(&val).unwrap(); + assert_eq!( + Element::read_first("When::2024-06-15T12:00:00-00:00"), + Element::read_first(&ion) + ); + let roundtrip: Wrapper = from_ion(&ion).unwrap(); + assert_eq!(val, roundtrip); + } + } } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index eafe8375..dd43894f 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -87,12 +87,12 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { type Ok = (); type Error = IonError; - type SerializeSeq = SeqWriter; + type SerializeSeq = SeqWriter>; type SerializeTuple = SeqWriter>; type SerializeTupleStruct = SeqWriter>; type SerializeTupleVariant = SeqWriter>; - type SerializeMap = MapWriter; - type SerializeStruct = MapWriter; + type SerializeMap = MapWriter>; + type SerializeStruct = MapWriter>; type SerializeStructVariant = MapWriter>; /// Determine whether Serialize implementations should serialize in human-readable form. @@ -103,7 +103,9 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { /// Serialize a boolean to a bool value fn serialize_bool(self, v: bool) -> Result { - self.value_writer.write(v) + self.value_writer + .with_annotations(self.annotations)? + .write(v) } /// Serialize all integer types using the `Integer` intermediary type. @@ -163,7 +165,9 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { } fn serialize_f32(self, v: f32) -> Result { - self.value_writer.write(v) + self.value_writer + .with_annotations(self.annotations)? + .write(v) } fn serialize_f64(self, v: f64) -> Result { @@ -253,7 +257,9 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { // The assert statement above that compares the sizes of the Decimal and value types assert_eq!(std::mem::size_of_val(value), std::mem::size_of::()); let decimal = unsafe { std::mem::transmute_copy::<&T, &Decimal>(&value) }; - self.value_writer.write_decimal(decimal) + self.value_writer + .with_annotations(self.annotations)? + .write_decimal(decimal) } else { value.serialize(self) } @@ -275,7 +281,10 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { fn serialize_seq(self, _len: Option) -> Result { Ok(SeqWriter { - seq_writer: self.value_writer.list_writer()?, + seq_writer: self + .value_writer + .with_annotations(self.annotations)? + .list_writer()?, is_human_readable: self.is_human_readable, }) } @@ -328,7 +337,10 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { fn serialize_map(self, _len: Option) -> Result { Ok(MapWriter { - map_writer: self.value_writer.struct_writer()?, + map_writer: self + .value_writer + .with_annotations(self.annotations)? + .struct_writer()?, is_human_readable: self.is_human_readable, }) } @@ -339,7 +351,10 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> { _len: usize, ) -> Result { Ok(MapWriter { - map_writer: self.value_writer.struct_writer()?, + map_writer: self + .value_writer + .with_annotations(self.annotations)? + .struct_writer()?, is_human_readable: self.is_human_readable, }) }