From 55f06146461943582663abad7156fba0d259b62b Mon Sep 17 00:00:00 2001 From: Khushboo <68757952+desaikd@users.noreply.github.com> Date: Wed, 3 Apr 2024 12:43:17 -0700 Subject: [PATCH] Adds support for parameterized Rust enums in serde (#733) --- src/serde/de.rs | 11 +++++--- src/serde/mod.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++--- src/serde/ser.rs | 12 ++++----- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/serde/de.rs b/src/serde/de.rs index f9b3fb5c..f1adcaa6 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -401,8 +401,8 @@ impl<'a, 'de> de::Deserializer<'de> for ValueDeserializer<'a, 'de> { use IonType::*; match self.value.ion_type() { String => visitor.visit_enum(UnitVariantAccess::new(self)), - Struct => visitor.visit_enum(VariantAccess::new(self)), - _ => IonResult::decoding_error("expected a string or struct enum representation"), + // All the parameterized Rust enums uses annotations for representing enum variant + _ => visitor.visit_enum(VariantAccess::new(self)), } } @@ -410,7 +410,12 @@ impl<'a, 'de> de::Deserializer<'de> for ValueDeserializer<'a, 'de> { where V: Visitor<'de>, { - visitor.visit_str(self.value.read()?.expect_text()?) + // annotations are currently only supported with parameterized Rust enums + if let Some(annotation) = self.value.annotations().next() { + visitor.visit_str(annotation?.text().unwrap()) + } else { + visitor.visit_str(self.value.read()?.expect_text()?) + } } fn deserialize_ignored_any(self, visitor: V) -> Result diff --git a/src/serde/mod.rs b/src/serde/mod.rs index d7fa90c7..a75c1c84 100644 --- a/src/serde/mod.rs +++ b/src/serde/mod.rs @@ -31,17 +31,20 @@ //!| list | vector | seq | //!| null | None | unit | //! -//! ## Mapping of serde data types to Ion data types +//! ## Mapping of serde data types to Ion representation //! -//!| Serde data type | Ion data type | +//!| Serde data type | Ion representation | //!|--------------------------------------------------------------|---------------------------------------------| //!| u64, i64, u32, i32, u16, i16, u8, i8 | int | //!| char, string, unit_variant | string | //!| byte-array | blob | //!| option | None - null, Some - based on other mappings | //!| unit, unit_struct | null | -//!| seq, tuple, tuple_struct, tuple_variant | list | -//!| newtype_struct, newtype_variant, map, struct, struct_variant | struct | +//!| seq, tuple, tuple_struct | list | +//!| newtype_struct, map, struct | struct | +//!| newtype_variant | variant value with annotation | +//!| struct_variant | struct with annotation | +//!| tuple_variant | list with annotation | //! //! _Note: Since the serde framework doesn't support [Ion decimal] and [Ion timestamp] types, distinct serialization //! and deserialization of these types are defined in this module. It uses `newtype_struct` with `$__ion_rs_decimal__` @@ -223,6 +226,9 @@ mod tests { #[serde_as(as = "crate::Timestamp")] date1: DateTime, nested_struct: NestedTest, + unit_struct: UnitStruct, + newtype_struct: NewTypeStruct, + tuple_struct: TupleStruct, optional: Option, } @@ -233,6 +239,18 @@ mod tests { str: String, } + #[serde_as] + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct UnitStruct; + + #[serde_as] + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct NewTypeStruct(i64); + + #[serde_as] + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct TupleStruct(i64, i64); + let datetime: DateTime = Utc::now().into(); let my_date0 = Utc::now(); let my_date = Timestamp::from(datetime); @@ -250,6 +268,10 @@ mod tests { boolean: true, str: "hello".to_string(), }, + + unit_struct: UnitStruct, + newtype_struct: NewTypeStruct(5), + tuple_struct: TupleStruct(5, 10), optional: None, }; @@ -269,6 +291,41 @@ mod tests { assert_eq!(back_result.date1, datetime.clone()); assert!(back_result.nested_struct.boolean); assert_eq!(&back_result.nested_struct.str, "hello"); + assert_eq!(back_result.unit_struct, UnitStruct); + assert_eq!(back_result.newtype_struct, NewTypeStruct(5)); + assert_eq!(back_result.tuple_struct, TupleStruct(5, 10)); assert_eq!(back_result.optional, None); } + + #[test] + fn test_enum() { + #[serde_as] + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum E { + Unit, + Newtype(u32), + Tuple(u32, u32), + Struct { a: u32 }, + } + + let i = r#""Unit""#; + let expected = E::Unit; + assert_eq!(expected, from_ion(i).unwrap()); + assert_eq!(i, to_string(&expected).unwrap()); + + let i = r#"Newtype::1"#; + let expected = E::Newtype(1); + assert_eq!(expected, from_ion(i).unwrap()); + assert_eq!(i, to_string(&expected).unwrap()); + + let i = r#"Tuple::[1, 2]"#; + let expected = E::Tuple(1, 2); + assert_eq!(expected, from_ion(i).unwrap()); + assert_eq!(i, to_string(&expected).unwrap()); + + let i = r#"Struct::{a: 1}"#; + let expected = E::Struct { a: 1 }; + assert_eq!(expected, from_ion(i).unwrap()); + assert_eq!(i, to_string(&expected).unwrap()); + } } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index f5749faf..ee467835 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -228,10 +228,8 @@ where where T: Serialize, { - self.writer.step_in(IonType::Struct)?; - self.writer.set_field_name(variant); - value.serialize(&mut *self)?; - self.writer.step_out() + self.writer.set_annotations(vec![variant]); + value.serialize(&mut *self) } fn serialize_seq(self, _len: Option) -> Result { @@ -257,9 +255,10 @@ where self, _name: &'static str, _variant_index: u32, - _variant: &'static str, + variant: &'static str, _len: usize, ) -> Result { + self.writer.set_annotations(vec![variant]); self.writer.step_in(IonType::List)?; Ok(self) } @@ -282,9 +281,10 @@ where self, _name: &'static str, _variant_index: u32, - _variant: &'static str, + variant: &'static str, _len: usize, ) -> Result { + self.writer.set_annotations(vec![variant]); self.writer.step_in(IonType::Struct)?; Ok(self) }