1use proc_macro2::{Span, TokenStream};
2use quote::{format_ident, quote};
3use syn::{punctuated::Punctuated, spanned::Spanned, Data, DeriveInput, Error, Field};
4use zvariant_utils::macros;
5
6use crate::utils::*;
7
8fn dict_name_for_field(
9 f: &Field,
10 rename_attr: Option<String>,
11 rename_all_attr: Option<&str>,
12) -> Result<String, Error> {
13 let ident = f.ident.as_ref().unwrap().to_string();
14 rename_identifier(ident, f.span(), rename_attr, rename_all_attr)
15}
16
17pub fn expand_serialize_derive(input: DeriveInput) -> Result<TokenStream, Error> {
19 let StructAttributes { rename_all, .. } = StructAttributes::parse(&input.attrs)?;
20 let rename_all_str = rename_all.as_deref().unwrap_or("snake_case");
21 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
22 let name = &input.ident;
23 let helper = format_ident!("__SerializeDict{}", name);
24 let zv = zvariant_path();
25
26 let mut field_defs = Vec::new();
27 let mut field_inits = Vec::new();
28 if let Data::Struct(data) = &input.data {
29 for field in &data.fields {
30 let ident = field.ident.as_ref().unwrap();
31 let ty = &field.ty;
32 let FieldAttributes { rename } = FieldAttributes::parse(&field.attrs)?;
33 let dict_name = dict_name_for_field(field, rename, rename_all.as_deref())?;
34 let is_opt = macros::ty_is_option(ty);
35 if is_opt {
36 let as_value_opt_path = quote! { #zv::as_value::optional };
37 let as_value_opt_str = format!("{as_value_opt_path}");
38 field_defs.push(quote! {
39 #[serde(
40 rename = #dict_name,
41 with = #as_value_opt_str,
42 skip_serializing_if = "Option::is_none",
43 )]
44 #ident: &'a #ty
45 });
46 } else {
47 let as_value_path = quote! { #zv::as_value };
48 let as_value_str = format!("{as_value_path}");
49 field_defs.push(quote! {
50 #[serde(rename = #dict_name, with = #as_value_str)]
51 #ident: &'a #ty
52 });
53 }
54 field_inits.push(quote! { #ident: &self.#ident });
55 }
56 } else {
57 return Err(Error::new(input.span(), "only structs supported"));
58 }
59
60 Ok(quote! {
61 #[allow(deprecated)]
62 impl #impl_generics #zv::export::serde::ser::Serialize for #name #ty_generics #where_clause {
63 fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
64 where
65 S: #zv::export::serde::ser::Serializer,
66 {
67 use #zv::export::serde::Serialize;
68
69 #[derive(Serialize)]
70 #[serde(rename_all = #rename_all_str)]
71 struct #helper<'a> {
72 #[serde(skip)]
73 phantom: ::std::marker::PhantomData<&'a ()>,
74 #(#field_defs,)*
75 }
76
77 let helper = #helper {
78 phantom: ::std::marker::PhantomData,
79 #(#field_inits,)*
80 };
81
82 helper.serialize(serializer)
83 }
84 }
85 })
86}
87
88pub fn expand_deserialize_derive(input: DeriveInput) -> Result<TokenStream, Error> {
90 let StructAttributes {
91 rename_all,
92 deny_unknown_fields,
93 ..
94 } = StructAttributes::parse(&input.attrs)?;
95 let rename_all_str = rename_all.as_deref().unwrap_or("snake_case");
96 let zv = zvariant_path();
97
98 let mut generics = input.generics.clone();
100 let lifetime_param = syn::LifetimeParam {
101 attrs: Vec::new(),
102 lifetime: syn::Lifetime::new("'de", Span::call_site()),
103 colon_token: None,
104 bounds: Punctuated::new(),
105 };
106 generics
107 .params
108 .insert(0, syn::GenericParam::Lifetime(lifetime_param));
109
110 let (impl_generics, _ty_generics, where_clause) = generics.split_for_impl();
111 let (_, orig_ty_generics, _) = input.generics.split_for_impl();
112 let name = &input.ident;
113 let helper = format_ident!("__DeserializeDict{}", name);
114
115 let mut field_defs = Vec::new();
116 let mut field_assignments = Vec::new();
117 let mut non_optional_field_checks = Vec::new();
118 if let Data::Struct(data) = &input.data {
119 for field in &data.fields {
120 let ident = field.ident.as_ref().unwrap();
121 let ty = &field.ty;
122 let FieldAttributes { rename } = FieldAttributes::parse(&field.attrs)?;
123 let dict_name = dict_name_for_field(field, rename, rename_all.as_deref())?;
124 let is_opt = macros::ty_is_option(ty);
125
126 if is_opt {
127 let as_value_opt_path = quote! { #zv::as_value::optional };
128 let as_value_opt_str = format!("{as_value_opt_path}");
129 field_defs.push(quote! {
130 #[serde(rename = #dict_name, with = #as_value_opt_str, default)]
131 #ident: #ty
132 });
133 field_assignments.push(quote! { #ident: helper.#ident });
134 } else {
135 let as_value_opt_path = quote! { #zv::as_value::optional };
137 let as_value_opt_str = format!("{as_value_opt_path}");
138 field_defs.push(quote! {
139 #[serde(rename = #dict_name, with = #as_value_opt_str, default)]
140 #ident: Option<#ty>
141 });
142
143 non_optional_field_checks.push(quote! {
145 if helper.#ident.is_none() {
146 return Err(<D::Error as #zv::export::serde::de::Error>::missing_field(#dict_name));
147 }
148 });
149
150 field_assignments.push(quote! { #ident: helper.#ident.unwrap() });
152 }
153 }
154 } else {
155 return Err(Error::new(input.span(), "only structs supported"));
156 }
157
158 let deny_attr = if deny_unknown_fields {
159 quote! { , deny_unknown_fields }
160 } else {
161 quote! {}
162 };
163
164 Ok(quote! {
165 #[allow(deprecated)]
166 impl #impl_generics #zv::export::serde::de::Deserialize<'de> for #name #orig_ty_generics
167 #where_clause
168 {
169 fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
170 where
171 D: #zv::export::serde::de::Deserializer<'de>,
172 {
173 use #zv::export::serde::Deserialize;
174
175 #[derive(Deserialize, Default)]
176 #[serde(default, rename_all = #rename_all_str #deny_attr)]
177 struct #helper {
178 #(#field_defs,)*
179 }
180
181 let helper = #helper::deserialize(deserializer)?;
182
183 #(#non_optional_field_checks)*
185
186 Ok(Self {
187 #(#field_assignments,)*
188 })
189 }
190 }
191 })
192}