Skip to content

Commit

Permalink
nanoserde: add serialize_bin_with, deserialize_bin_with
Browse files Browse the repository at this point in the history
  • Loading branch information
Adjective-Object committed Oct 4, 2024
1 parent d5afe28 commit 6e69163
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 13 deletions.
4 changes: 2 additions & 2 deletions derive/src/serde_bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub fn derive_ser_bin_struct(struct_: &Struct) -> TokenStream {

for field in &struct_.fields {
let field_name: &String = field.field_name.as_ref().unwrap();
let field_serializer = shared::attrs_serialize_bin_with(&field.attributes);
let field_serializer = crate::shared::attrs_serialize_bin_with(&field.attributes);

if let Some(proxy) = crate::shared::attrs_proxy(&field.attributes) {
l!(
Expand Down Expand Up @@ -91,7 +91,7 @@ pub fn derive_ser_bin_struct_unnamed(struct_: &Struct) -> TokenStream {
let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "SerBin");

for (n, field) in struct_.fields.iter().enumerate() {
let field_serializer = shared::attrs_serialize_bin_with(&field.attributes);
let field_serializer = crate::shared::attrs_serialize_bin_with(&field.attributes);

if let Some(proxy) = crate::shared::attrs_proxy(&field.attributes) {
l!(body, "let proxy: {} = Into::into(&self.{});", proxy, n);
Expand Down
49 changes: 38 additions & 11 deletions derive/src/serde_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub fn derive_ser_json_struct(struct_: &Struct) -> TokenStream {

if struct_.fields.len() >= 1 {
for (_index, field) in struct_.fields.iter().enumerate() {
let serialize_json_with = shared::attrs_serialize_json_with(&field.attributes);

let struct_fieldname = field.field_name.clone().unwrap();
let json_fieldname =
shared::attrs_rename(&field.attributes).unwrap_or_else(|| struct_fieldname.clone());
Expand All @@ -60,12 +62,16 @@ pub fn derive_ser_json_struct(struct_: &Struct) -> TokenStream {
let proxy_attr = crate::shared::attrs_proxy(&field.attributes);
let struct_null_on_none = shared::attrs_serialize_none_as_null(&struct_.attributes);
let field_null_on_none = shared::attrs_serialize_none_as_null(&field.attributes);
let null_on_none = (field_null_on_none || struct_null_on_none) && proxy_attr.is_none();
let field_header = &format!("if first_field_was_serialized {{
let null_on_none =
(field_null_on_none || struct_null_on_none) && proxy_attr.is_none();
let field_header = &format!(
"if first_field_was_serialized {{
s.conl();
}};
first_field_was_serialized = true;
s.field(d+1, \"{}\");", json_fieldname);
s.field(d+1, \"{}\");",
json_fieldname
);
l!(
s,
"{}
Expand All @@ -92,9 +98,13 @@ pub fn derive_ser_json_struct(struct_: &Struct) -> TokenStream {
}};
first_field_was_serialized = true;
s.field(d+1,\"{}\");
{}.ser_json(d+1, s);",
{}",
json_fieldname,
proxied_field
if let Some(custom_serializer) = serialize_json_with {
format!("{}(&{}, d+1, s);", custom_serializer, proxied_field)
} else {
format!("{}.ser_json(d+1, s);", proxied_field)
}
);
}
}
Expand Down Expand Up @@ -126,6 +136,7 @@ pub fn derive_de_json_named(name: &str, defaults: bool, fields: &[Field]) -> Tok
let mut local_vars = Vec::new();
let mut struct_field_names = Vec::new();
let mut json_field_names = Vec::new();
// Vec of (json_field_name, local_var_name, custom_initializer)
let mut matches = Vec::new();
let mut unwraps = Vec::new();

Expand All @@ -136,6 +147,8 @@ pub fn derive_de_json_named(name: &str, defaults: bool, fields: &[Field]) -> Tok
let localvar = format!("_{}", struct_fieldname);
let field_attr_default = shared::attrs_default(&field.attributes);
let field_attr_default_with = shared::attrs_default_with(&field.attributes);
let deserialize_json_with = shared::attrs_deserialize_json_with(&field.attributes);

let default_val = if let Some(v) = field_attr_default {
if let Some(mut val) = v {
if field.ty.base() == "String"
Expand Down Expand Up @@ -198,7 +211,11 @@ pub fn derive_de_json_named(name: &str, defaults: bool, fields: &[Field]) -> Tok
localvar, proxified_t, struct_fieldname
));
}
matches.push((json_fieldname.clone(), localvar.clone()));
matches.push((
json_fieldname.clone(),
localvar.clone(),
deserialize_json_with,
));
local_vars.push(localvar);
} else {
unwraps.push(default_val.unwrap_or_else(|| String::from("Default::default()")));
Expand All @@ -217,12 +234,16 @@ pub fn derive_de_json_named(name: &str, defaults: bool, fields: &[Field]) -> Tok

if json_field_names.len() != 0 {
l!(r, "match AsRef::<str>::as_ref(&s.strbuf) {");
for (json_field_name, local_var) in matches.iter() {
for (json_field_name, local_var, deserialize_with) in matches.iter() {
l!(
r,
"\"{}\" => {{s.next_colon(i) ?;{} = Some(DeJson::de_json(s, i) ?)}},",
"\"{}\" => {{s.next_colon(i) ?;{} = Some({} ?)}},",
json_field_name,
local_var
local_var,
deserialize_with
.as_ref()
.map(|deserializer_name| format!("{}(s, i)", deserializer_name))
.unwrap_or_else(|| "DeJson::de_json(s, i)".to_string())
);
}
// TODO: maybe introduce "exhaustive" attribute?
Expand Down Expand Up @@ -591,8 +612,14 @@ pub fn derive_de_json_struct_unnamed(struct_: &Struct) -> TokenStream {

let transparent = shared::attrs_transparent(&struct_.attributes);

for _ in &struct_.fields {
l!(body, "{ let r = DeJson::de_json(s, i)?;");
for field in &struct_.fields {
let deserialize_json_with = shared::attrs_deserialize_json_with(&field.attributes);
if let Some(deserialize_json_with) = deserialize_json_with {
l!(body, "{{ let r = {}(s, i)?;", deserialize_json_with);
} else {
l!(body, "{ let r = DeJson::de_json(s, i)?;");
}

if struct_.fields.len() != 1 {
l!(body, " s.eat_comma_block(i)?;");
}
Expand Down
47 changes: 47 additions & 0 deletions tests/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,53 @@ fn de_field_default() {
assert_eq!(test.foo2.x, 3);
}

#[test]
fn de_field_deserialize_json_with() {
use nanoserde::DeJsonState;
fn custom_deserializer(
s: &mut DeJsonState,
i: &mut std::str::Chars,
) -> Result<String, nanoserde::DeJsonErr> {
let c: String = DeJson::de_json(s, i)?;
Ok(c + "--custom-deserializer")
}

#[derive(DeJson)]
pub struct Test {
#[nserde(deserialize_json_with = "custom_deserializer")]
a: String,
}

let json = r#"{
"a": "input",
}"#;

let test: Test = DeJson::deserialize_json(json).unwrap();
assert_eq!(test.a, "input--custom-deserializer");
}

#[test]
fn de_field_serialize_json_with() {
use nanoserde::SerJsonState;
fn custom_serializer(value: &i32, _: usize, s: &mut SerJsonState) {
s.out.push_str(&format!("\"{}--custom-serializer\"", value));
}

#[derive(SerJson)]
struct Test {
#[nserde(serialize_json_with = "custom_serializer")]
a: i32,
b: i32,
}

let value = Test { a: 1, b: 2 };

assert_eq!(
SerJson::serialize_json(&value),
r#"{"a":"1--custom-serializer","b":2}"#
);
}

#[test]
fn ser_none_as_null() {
#[derive(SerJson)]
Expand Down

0 comments on commit 6e69163

Please sign in to comment.