Implement deserialize_with

This commit is contained in:
Sosthène Guédon
2025-06-05 10:42:07 +02:00
committed by sosthene-nitrokey
parent 1ba7e85dfc
commit a7f9c680fa
2 changed files with 56 additions and 2 deletions
+34 -1
View File
@@ -181,12 +181,45 @@ fn match_fields(fields: &[parse::Field], offset: usize) -> Vec<proc_macro2::Toke
let label = field.label.clone();
let ident = format_ident!("{}", &field.label);
let index = field.index + offset;
let next_value = match &field.deserialize_with {
Some(f) => {
let ty = &field.ty;
quote!({
struct __DeserializeWith< 'de> {
value: #ty,
lifetime: ::core::marker::PhantomData<&'de ()>,
}
impl<'de> serde::Deserialize<'de> for __DeserializeWith<'de> {
fn deserialize<__D>(
__deserializer: __D,
) -> Result<Self, __D::Error>
where
__D: serde::Deserializer<'de>,
{
Ok(__DeserializeWith {
value: #f(__deserializer)?,
lifetime: ::core::marker::PhantomData,
})
}
}
let __DeserializeWith { value, lifetime: _ } = map.next_value()?;
value
}
)
}
None => quote!(map.next_value()?),
};
quote! {
#index => {
if #ident.is_some() {
return Err(serde::de::Error::duplicate_field(#label));
}
#ident = Some(map.next_value()?);
let next_value = #next_value;
#ident = Some(next_value);
},
}
})
+22 -1
View File
@@ -418,7 +418,7 @@ mod generics {
use heapless::String;
use serde_byte_array::ByteArray;
use serde_bytes::Bytes;
use serde_test::assert_ser_tokens;
use serde_test::{assert_de_tokens, assert_ser_tokens};
#[derive(PartialEq, Debug, SerializeIndexed, DeserializeIndexed)]
#[serde_indexed(offset = 1)]
@@ -544,4 +544,25 @@ mod generics {
],
)
}
#[test]
fn deserialize_with() {
#[derive(serde_indexed::DeserializeIndexed, PartialEq, Eq, Debug)]
struct SerializeWith {
#[serde(deserialize_with = "serde_bytes::deserialize")]
data: Vec<u8>,
}
let value = SerializeWith { data: vec![0; 128] };
assert_de_tokens(
&value,
&[
Token::Map { len: Some(1) },
Token::U64(0),
Token::Bytes(&[0; 128]),
Token::MapEnd,
],
)
}
}