Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions src/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,4 +474,119 @@ mod tests {
assert_eq!(&from_ion::<IpAddr, _>(s).unwrap(), &ip);
assert_eq!(&from_ion::<IpAddr, _>(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<u32>),
Dict(BTreeMap<String, u32>),
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);
}
}
}
33 changes: 24 additions & 9 deletions src/serde/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> {
type Ok = ();
type Error = IonError;

type SerializeSeq = SeqWriter<V>;
type SerializeSeq = SeqWriter<V::AnnotatedValueWriter<'a>>;
type SerializeTuple = SeqWriter<V::AnnotatedValueWriter<'a>>;
type SerializeTupleStruct = SeqWriter<V::AnnotatedValueWriter<'a>>;
type SerializeTupleVariant = SeqWriter<V::AnnotatedValueWriter<'a>>;
type SerializeMap = MapWriter<V>;
type SerializeStruct = MapWriter<V>;
type SerializeMap = MapWriter<V::AnnotatedValueWriter<'a>>;
type SerializeStruct = MapWriter<V::AnnotatedValueWriter<'a>>;
type SerializeStructVariant = MapWriter<V::AnnotatedValueWriter<'a>>;

/// Determine whether Serialize implementations should serialize in human-readable form.
Expand All @@ -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::Ok, Self::Error> {
self.value_writer.write(v)
self.value_writer
.with_annotations(self.annotations)?
.write(v)
}

/// Serialize all integer types using the `Integer` intermediary type.
Expand Down Expand Up @@ -163,7 +165,9 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> {
}

fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
self.value_writer.write(v)
self.value_writer
.with_annotations(self.annotations)?
.write(v)
}

fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
Expand Down Expand Up @@ -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::<Decimal>());
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)
}
Expand All @@ -275,7 +281,10 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> {

fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
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,
})
}
Expand Down Expand Up @@ -328,7 +337,10 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> {

fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
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,
})
}
Expand All @@ -339,7 +351,10 @@ impl<'a, V: ValueWriter + 'a> ser::Serializer for ValueSerializer<'a, V> {
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
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,
})
}
Expand Down
Loading