apache_avro_derive/attributes/
mod.rs1use crate::case::RenameRule;
19use darling::{FromAttributes, FromMeta};
20use proc_macro2::{Span, TokenStream};
21use quote::quote;
22use syn::{AttrStyle, Attribute, Expr, Ident, Path, spanned::Spanned};
23
24mod avro;
25mod serde;
26
27#[derive(Default)]
28pub struct NamedTypeOptions {
29 pub name: String,
30 pub doc: Option<String>,
31 pub aliases: Vec<String>,
32 pub rename_all: RenameRule,
33 pub transparent: bool,
34 pub default: TokenStream,
35}
36
37impl NamedTypeOptions {
38 pub fn new(
39 ident: &Ident,
40 attributes: &[Attribute],
41 span: Span,
42 ) -> Result<Self, Vec<syn::Error>> {
43 let avro =
44 avro::ContainerAttributes::from_attributes(attributes).map_err(darling_to_syn)?;
45 let serde =
46 serde::ContainerAttributes::from_attributes(attributes).map_err(darling_to_syn)?;
47
48 avro.deprecated(span);
50
51 let mut errors = Vec::new();
53
54 if serde.tag.is_some()
56 || serde.content.is_some()
57 || serde.untagged
58 || serde.variant_identifier
59 || serde.field_identifier
60 {
61 errors.push(syn::Error::new(
62 span,
63 "AvroSchema derive does not support changing the tagging Serde generates (`tag`, `content`, `untagged`, `variant_identifier`, `field_identifier`)",
64 ));
65 }
66 if serde.remote.is_some() {
67 errors.push(syn::Error::new(
68 span,
69 "AvroSchema derive does not support the Serde `remote` attribute",
70 ));
71 }
72 if serde.rename_all.deserialize != serde.rename_all.serialize {
73 errors.push(syn::Error::new(
74 span,
75 r#"AvroSchema derive does not support different rename rules for serializing and deserializing (`rename_all(serialize = "..", deserialize = "..")`)"#
76 ));
77 }
78
79 if avro.name.is_some() && avro.name != serde.rename {
81 errors.push(syn::Error::new(
82 span,
83 r#"#[avro(name = "..")] must match #[serde(rename = "..")], it's also deprecated. Please use only `#[serde(rename = "..")]`"#,
84 ));
85 }
86 if avro.rename_all != RenameRule::None && serde.rename_all.serialize != avro.rename_all {
87 errors.push(syn::Error::new(
88 span,
89 r#"#[avro(rename_all = "..")] must match #[serde(rename_all = "..")], it's also deprecated. Please use only `#[serde(rename_all = "..")]`"#,
90 ));
91 }
92 if serde.transparent
93 && (serde.rename.is_some()
94 || avro.name.is_some()
95 || avro.namespace.is_some()
96 || avro.doc.is_some()
97 || !avro.alias.is_empty()
98 || avro.rename_all != RenameRule::None
99 || serde.rename_all.serialize != RenameRule::None
100 || serde.rename_all.deserialize != RenameRule::None)
101 {
102 errors.push(syn::Error::new(
103 span,
104 "AvroSchema: #[serde(transparent)] is incompatible with all other attributes",
105 ));
106 }
107
108 if !errors.is_empty() {
109 return Err(errors);
110 }
111
112 let name = serde.rename.unwrap_or(ident.to_string());
113 let full_schema_name = vec![avro.namespace, Some(name)]
114 .into_iter()
115 .flatten()
116 .collect::<Vec<String>>()
117 .join(".");
118
119 let doc = avro.doc.or_else(|| extract_rustdoc(attributes));
120
121 let default = match avro.default {
122 None => quote! { None },
123 Some(default_value) => {
124 let _: serde_json::Value =
125 serde_json::from_str(&default_value[..]).map_err(|e| {
126 vec![syn::Error::new(
127 ident.span(),
128 format!("Invalid Avro `default` JSON: \n{e}"),
129 )]
130 })?;
131 quote! {
132 Some(::serde_json::from_str(#default_value).expect(format!("Invalid JSON: {:?}", #default_value).as_str()))
133 }
134 }
135 };
136
137 Ok(Self {
138 name: full_schema_name,
139 doc,
140 aliases: avro.alias,
141 rename_all: serde.rename_all.serialize,
142 transparent: serde.transparent,
143 default,
144 })
145 }
146}
147
148pub struct VariantOptions {
149 pub rename: Option<String>,
150}
151
152impl VariantOptions {
153 pub fn new(attributes: &[Attribute], span: Span) -> Result<Self, Vec<syn::Error>> {
154 let avro = avro::VariantAttributes::from_attributes(attributes).map_err(darling_to_syn)?;
155 let serde =
156 serde::VariantAttributes::from_attributes(attributes).map_err(darling_to_syn)?;
157
158 avro.deprecated(span);
160
161 let mut errors = Vec::new();
163
164 if serde.other || serde.untagged {
166 errors.push(syn::Error::new(
167 span,
168 "AvroSchema derive does not support changing the tagging Serde generates (`other`, `untagged`)",
169 ));
170 }
171
172 if avro.rename.is_some() && serde.rename != avro.rename {
174 errors.push(syn::Error::new(
175 span,
176 r#"`#[avro(rename = "..")]` must match `#[serde(rename = "..")]`, it's also deprecated. Please use only `#[serde(rename = "..")]`"#
177 ));
178 }
179
180 if !errors.is_empty() {
181 return Err(errors);
182 }
183
184 Ok(Self {
185 rename: serde.rename,
186 })
187 }
188}
189
190#[derive(Debug, PartialEq, Default, Clone)]
192pub enum With {
193 #[default]
195 Trait,
196 Serde(Path),
198 Expr(Expr),
200}
201
202impl With {
203 fn from_avro_and_serde(
204 avro: &avro::With,
205 serde: Option<&String>,
206 span: Span,
207 ) -> Result<Self, syn::Error> {
208 match &avro {
209 avro::With::Trait => Ok(Self::Trait),
210 avro::With::Serde => {
211 if let Some(serde) = serde {
212 let path = Path::from_string(serde).map_err(|err| {
213 syn::Error::new(
214 span,
215 format!(
216 r#"AvroSchema: Expected a path for `#[serde(with = "..")]`: {err:?}"#
217 ),
218 )
219 })?;
220 Ok(Self::Serde(path))
221 } else {
222 Err(syn::Error::new(
223 span,
224 r#"`#[avro(with)]` requires `#[serde(with = "some_module")]` or provide a function to call `#[avro(with = some_fn)]`"#,
225 ))
226 }
227 }
228 avro::With::Expr(expr) => Ok(Self::Expr(expr.clone())),
229 }
230 }
231}
232#[derive(Debug, PartialEq, Default)]
234pub enum FieldDefault {
235 #[default]
237 Trait,
238 Disabled,
240 Value(String),
242}
243
244impl FromMeta for FieldDefault {
245 fn from_string(value: &str) -> darling::Result<Self> {
246 Ok(Self::Value(value.to_string()))
247 }
248
249 fn from_bool(value: bool) -> darling::Result<Self> {
250 if value {
251 Err(darling::Error::custom(
252 "Expected `false` or a JSON string, got `true`",
253 ))
254 } else {
255 Ok(Self::Disabled)
256 }
257 }
258}
259
260#[derive(Default)]
261pub struct FieldOptions {
262 pub doc: Option<String>,
263 pub default: FieldDefault,
264 pub alias: Vec<String>,
265 pub rename: Option<String>,
266 pub skip: bool,
267 pub flatten: bool,
268 pub with: With,
269}
270
271impl FieldOptions {
272 pub fn new(attributes: &[Attribute], span: Span) -> Result<Self, Vec<syn::Error>> {
273 let mut avro =
274 avro::FieldAttributes::from_attributes(attributes).map_err(darling_to_syn)?;
275 let mut serde =
276 serde::FieldAttributes::from_attributes(attributes).map_err(darling_to_syn)?;
277 avro.alias.sort();
279 serde.alias.sort();
280
281 avro.deprecated(span);
283
284 let mut errors = Vec::new();
286
287 if serde.getter.is_some() {
289 errors.push(syn::Error::new(
290 span,
291 "AvroSchema derive does not support the Serde `getter` attribute",
292 ));
293 }
294
295 if avro.skip && !(serde.skip || (serde.skip_serializing && serde.skip_deserializing)) {
297 errors.push(syn::Error::new(
298 span,
299 "`#[avro(skip)]` requires `#[serde(skip)]`, it's also deprecated. Please use only `#[serde(skip)]`"
300 ));
301 }
302 if avro.flatten && !serde.flatten {
303 errors.push(syn::Error::new(
304 span,
305 "`#[avro(flatten)]` requires `#[serde(flatten)]`, it's also deprecated. Please use only `#[serde(flatten)]`"
306 ));
307 }
308 if avro.rename.is_some() && serde.rename != avro.rename {
310 errors.push(syn::Error::new(
311 span,
312 r#"`#[avro(rename = "..")]` must match `#[serde(rename = "..")]`, it's also deprecated. Please use only `#[serde(rename = "..")]`"#
313 ));
314 }
315 if !avro.alias.is_empty() && serde.alias != avro.alias {
316 errors.push(syn::Error::new(
317 span,
318 r#"`#[avro(alias = "..")]` must match `#[serde(alias = "..")]`, it's also deprecated. Please use only `#[serde(alias = "..")]`"#
319 ));
320 }
321
322 let with = match With::from_avro_and_serde(&avro.with, serde.with.as_ref(), span) {
323 Ok(with) => with,
324 Err(error) => {
325 errors.push(error);
326 With::Trait
328 }
329 };
330 if with != With::Trait && avro.default == FieldDefault::Trait {
333 avro.default = FieldDefault::Disabled;
334 }
335
336 if ((serde.skip_serializing && !serde.skip_deserializing)
337 || serde.skip_serializing_if.is_some())
338 && avro.default == FieldDefault::Disabled
339 {
340 errors.push(syn::Error::new(
341 span,
342 "`#[serde(skip_serializing)]` and `#[serde(skip_serializing_if)]` are incompatible with `#[avro(default = false)]`"
343 ));
344 }
345
346 if !errors.is_empty() {
347 return Err(errors);
348 }
349
350 let doc = avro.doc.or_else(|| extract_rustdoc(attributes));
351
352 Ok(Self {
353 doc,
354 default: avro.default,
355 alias: serde.alias,
356 rename: serde.rename,
357 skip: serde.skip || (serde.skip_serializing && serde.skip_deserializing),
358 flatten: serde.flatten,
359 with,
360 })
361 }
362}
363
364fn extract_rustdoc(attributes: &[Attribute]) -> Option<String> {
365 let doc = attributes
366 .iter()
367 .filter(|attr| attr.style == AttrStyle::Outer && attr.path().is_ident("doc"))
368 .filter_map(|attr| {
369 let name_value = attr.meta.require_name_value();
370 match name_value {
371 Ok(name_value) => match &name_value.value {
372 syn::Expr::Lit(expr_lit) => match expr_lit.lit {
373 syn::Lit::Str(ref lit_str) => Some(lit_str.value().trim().to_string()),
374 _ => None,
375 },
376 _ => None,
377 },
378 Err(_) => None,
379 }
380 })
381 .collect::<Vec<String>>()
382 .join("\n");
383 if doc.is_empty() { None } else { Some(doc) }
384}
385
386fn darling_to_syn(e: darling::Error) -> Vec<syn::Error> {
387 let msg = format!("{e}");
388 let token_errors = e.write_errors();
389 vec![syn::Error::new(token_errors.span(), msg)]
390}
391
392#[cfg(nightly)]
393fn warn(span: Span, message: &str, help: &str) {
397 proc_macro::Diagnostic::spanned(span.unwrap(), proc_macro::Level::Warning, message)
398 .help(help)
399 .emit();
400}
401
402#[cfg(not(nightly))]
403fn warn(_span: Span, _message: &str, _help: &str) {}