From ad8790b22ad1c1a38095c1d8c38fee096c510545 Mon Sep 17 00:00:00 2001 From: Fedor Logachev Date: Thu, 31 Aug 2023 16:50:32 -0600 Subject: [PATCH] json: Allow proxies for optional types --- derive/src/serde_json.rs | 37 +++++++++++--------- tests/json.rs | 75 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 16 deletions(-) diff --git a/derive/src/serde_json.rs b/derive/src/serde_json.rs index de71f91..6854e31 100644 --- a/derive/src/serde_json.rs +++ b/derive/src/serde_json.rs @@ -25,6 +25,20 @@ pub fn derive_ser_json_proxy(proxy_type: &str, type_: &str) -> TokenStream { .unwrap() } +fn ser_proxy_guard(fieldname: &str, field: &Field) -> String { + if let Some(proxy) = crate::shared::attrs_proxy(&field.attributes) { + if field.ty.base() == "Option" { + format!( + "{{{fieldname}.as_ref().map(|f| {{let proxy: {proxy} = Into::into(f);proxy}})}}" + ) + } else { + format!("{{let proxy: {proxy} = Into::into(&{fieldname});proxy}}",) + } + } else { + format!("{fieldname}") + } +} + pub fn derive_ser_json_struct(struct_: &Struct) -> TokenStream { let mut s = String::new(); let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "SerJson"); @@ -40,14 +54,7 @@ pub fn derive_ser_json_struct(struct_: &Struct) -> TokenStream { if skip { continue; } - let proxied_field = if let Some(proxy) = crate::shared::attrs_proxy(&field.attributes) { - format!( - "{{let proxy: {} = Into::into(&self.{});proxy}}", - proxy, struct_fieldname - ) - } else { - format!("self.{}", struct_fieldname) - }; + let proxied_field = ser_proxy_guard(&format!("self.{struct_fieldname}"), field); if field.ty.base() == "Option" { l!( @@ -135,7 +142,11 @@ pub fn derive_de_json_named(name: &str, defaults: bool, fields: &[Field]) -> Tok let skip = crate::shared::attrs_skip(&field.attributes); let proxified_t = if let Some(proxy) = proxy { - format!("From::<&{}>::from(&t)", proxy) + if field.ty.base() == "Option" { + format!("Some(From::<&{proxy}>::from(&t))") + } else { + format!("From::<&{proxy}>::from(&t)") + } } else { format!("t") }; @@ -276,13 +287,7 @@ pub fn derive_ser_json_enum(enum_: &Enum) -> TokenStream { let last = contents.fields.len() - 1; for (index, field) in contents.fields.iter().enumerate() { if let Some(name) = &&field.field_name { - let proxied_field = - if let Some(proxy) = crate::shared::attrs_proxy(&variant.attributes) { - format!("{{let proxy: {} = Into::into(&{});proxy}}", proxy, name) - } else { - format!("{}", name) - }; - + let proxied_field = ser_proxy_guard(name, field); if index == last { if field.ty.base() == "Option" { l!( diff --git a/tests/json.rs b/tests/json.rs index ae821c7..421296b 100644 --- a/tests/json.rs +++ b/tests/json.rs @@ -626,6 +626,81 @@ fn field_proxy() { assert!(test == test_deserialized); } +#[test] +fn field_option_proxy() { + #[derive(PartialEq, Clone, Debug)] + #[repr(u32)] + enum SomeEnum { + One, + Two, + Three, + } + + #[derive(PartialEq, Debug, DeJson, SerJson)] + #[nserde(transparent)] + pub struct U32(u32); + + impl From<&SomeEnum> for U32 { + fn from(e: &SomeEnum) -> U32 { + U32(e.clone() as u32) + } + } + impl From<&U32> for SomeEnum { + fn from(n: &U32) -> SomeEnum { + match n.0 { + 0 => SomeEnum::One, + 1 => SomeEnum::Two, + 2 => SomeEnum::Three, + _ => panic!(), + } + } + } + + #[derive(DeJson, SerJson, PartialEq, Debug)] + pub struct Test { + #[nserde(proxy = "U32")] + foo: Option, + #[nserde(proxy = "U32")] + bar: SomeEnum, + } + + let test = Test { + foo: Some(SomeEnum::Three), + bar: SomeEnum::Two, + }; + let bytes = SerJson::serialize_json(&test); + let test_deserialized = DeJson::deserialize_json(&bytes).unwrap(); + assert!(test == test_deserialized); + let test = Test { + foo: None, + bar: SomeEnum::One, + }; + let bytes = SerJson::serialize_json(&test); + let test_deserialized = DeJson::deserialize_json(&bytes).unwrap(); + assert!(test == test_deserialized); + + #[derive(DeJson, SerJson, PartialEq, Debug)] + enum Test2 { + //A(#[nserde(proxy = "U32")] Option), + B { + #[nserde(proxy = "U32")] + bar: Option, + }, + } + + // TODO + // let test = Test2::A(Some(SomeEnum::Three)); + // let bytes = SerJson::serialize_json(&test); + // let test_deserialized = DeJson::deserialize_json(&bytes).unwrap(); + // assert!(test == test_deserialized); + let test = Test2::B { + bar: Some(SomeEnum::One), + }; + let bytes = SerJson::serialize_json(&test); + let test_deserialized = DeJson::deserialize_json(&bytes).unwrap(); + assert!(test == test_deserialized); +} + #[test] fn tuple_struct() { #[derive(DeJson, SerJson, PartialEq)]