Implement serialize_with

This commit is contained in:
Sosthène Guédon
2025-06-05 10:42:07 +02:00
committed by sosthene-nitrokey
parent 431df81340
commit 1ba7e85dfc
4 changed files with 53 additions and 3 deletions
+1 -1
View File
@@ -23,6 +23,6 @@ heapless = { version = "0.7.16", default-features = false, features = ["serde"]
hex-literal = "0.4.1"
serde = { version = "1" }
serde-byte-array = "0.1.2"
serde_bytes = { version = "0.11.12", default-features = false }
serde_bytes = { version = "0.11.12" }
serde_cbor = { version = "0.11.0" }
serde_test = "1.0.176"
+28 -2
View File
@@ -44,16 +44,42 @@ fn serialize_fields(fields: &[parse::Field], offset: usize) -> Vec<proc_macro2::
.filter_map(|field| {
let index = field.index + offset;
let member = &field.member;
let serialize_member = match &field.serialize_with {
None => quote!(&self.#member),
Some(f) => {
let ty = &field.ty;
quote!({
struct __SerializeWith<'__lifetime> {
value: &'__lifetime #ty,
}
impl<'__lifetime> serde::Serialize for __SerializeWith<'__lifetime> {
fn serialize<__S>(
&self,
__s: __S,
) -> ::core::result::Result<__S::Ok, __S::Error>
where
__S: serde::Serializer,
{
#f(self.value, __s)
}
}
&__SerializeWith { value: &self.#member }
})
}
};
// println!("field {:?} index {:?}", &field.label, field.index);
match &field.skip_serializing_if {
Skip::If(path) => Some(quote! {
if !#path(&self.#member) {
map.serialize_entry(&#index, &self.#member)?;
map.serialize_entry(&#index, #serialize_member)?;
}
}),
Skip::Always => None,
Skip::Never => Some(quote! {
map.serialize_entry(&#index, &self.#member)?;
map.serialize_entry(&#index, #serialize_member)?;
}),
}
})
+2
View File
@@ -38,6 +38,7 @@ pub struct Field {
pub skip_serializing_if: Skip,
pub serialize_with: Option<syn::ExprPath>,
pub deserialize_with: Option<syn::ExprPath>,
pub ty: syn::Type,
}
fn parse_meta(attrs: &mut StructAttrs, meta: ParseNestedMeta) -> Result<()> {
@@ -190,6 +191,7 @@ fn fields_from_ast(
},
index: current_index,
// TODO: make this... more concise? handle errors? the thing with the spans?
ty: field.ty.clone(),
skip_serializing_if,
serialize_with,
deserialize_with,
+22
View File
@@ -418,6 +418,7 @@ mod generics {
use heapless::String;
use serde_byte_array::ByteArray;
use serde_bytes::Bytes;
use serde_test::assert_ser_tokens;
#[derive(PartialEq, Debug, SerializeIndexed, DeserializeIndexed)]
#[serde_indexed(offset = 1)]
@@ -522,4 +523,25 @@ mod generics {
assert_eq!(deserialized, example);
}
#[test]
fn serialize_with() {
#[derive(serde_indexed::SerializeIndexed)]
struct SerializeWith {
#[serde(serialize_with = "serde_bytes::serialize")]
data: Vec<u8>,
}
let value = SerializeWith { data: vec![0; 128] };
assert_ser_tokens(
&value,
&[
Token::Map { len: Some(1) },
Token::U64(0),
Token::Bytes(&[0; 128]),
Token::MapEnd,
],
)
}
}