Skip to content

Commit

Permalink
json: Allow proxies for optional types
Browse files Browse the repository at this point in the history
  • Loading branch information
not-fl3 committed Sep 1, 2023
1 parent 5cddd0d commit 4f359fd
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 16 deletions.
37 changes: 21 additions & 16 deletions derive/src/serde_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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!(
Expand Down Expand Up @@ -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")
};
Expand Down Expand Up @@ -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!(
Expand Down
75 changes: 75 additions & 0 deletions tests/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<SomeEnum>,
#[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<SomeEnum>),
B {
#[nserde(proxy = "U32")]
bar: Option<SomeEnum>,
},
}

// 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)]
Expand Down

0 comments on commit 4f359fd

Please sign in to comment.