From 1ba7e85dfc32b372d55870d2e2de923420aa33d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 24 Jun 2024 16:40:03 +0200 Subject: [PATCH] Implement serialize_with --- Cargo.toml | 2 +- src/lib.rs | 30 ++++++++++++++++++++++++++++-- src/parse.rs | 2 ++ tests/basics.rs | 22 ++++++++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b2d4684..f8d0b1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/lib.rs b/src/lib.rs index 360dc7c..dee75ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,16 +44,42 @@ fn serialize_fields(fields: &[parse::Field], offset: usize) -> Vec 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)?; }), } }) diff --git a/src/parse.rs b/src/parse.rs index 96c0f55..f5e51fe 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -38,6 +38,7 @@ pub struct Field { pub skip_serializing_if: Skip, pub serialize_with: Option, pub deserialize_with: Option, + 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, diff --git a/tests/basics.rs b/tests/basics.rs index 26f3c04..97f0d7e 100644 --- a/tests/basics.rs +++ b/tests/basics.rs @@ -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, + } + + 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, + ], + ) + } }