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