1#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png",
5 html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png"
6)]
7#![recursion_limit = "256"]
8
9use std::str::FromStr;
10
11use proc_macro2::{Span, TokenStream};
12use quote::{ToTokens, quote};
13use syn::spanned::Spanned;
14use syn::{Data, Error, Lit, LitStr};
15use synstructure::decl_derive;
16
17mod utils;
18
19use self::utils::SynstructureExt as _;
20
21#[derive(Debug, Clone, Copy)]
22enum Trait {
23 From,
24 To,
25}
26
27decl_derive!([Empty, attributes(metastructure)] => derive_empty);
28decl_derive!([IntoValue, attributes(metastructure)] => derive_to_value);
29decl_derive!([FromValue, attributes(metastructure)] => derive_from_value);
30
31fn derive_empty(mut s: synstructure::Structure<'_>) -> syn::Result<TokenStream> {
32 let _ = s.add_bounds(synstructure::AddBounds::Generics);
33
34 let is_empty_arms = s.try_each_variant(|variant| {
35 let mut is_tuple_struct = false;
36 let mut cond = quote!(true);
37 for (index, bi) in variant.bindings().iter().enumerate() {
38 let field_attrs = parse_field_attributes(index, bi.ast(), &mut is_tuple_struct)?;
39 let ident = &bi.binding;
40 if field_attrs.additional_properties {
41 cond = quote! {
42 #cond && #bi.values().all(::relay_protocol::Empty::is_empty)
43 };
44 } else {
45 cond = quote! {
46 #cond && ::relay_protocol::Empty::is_empty(#ident)
47 };
48 }
49 }
50
51 Ok(cond)
52 })?;
53
54 let is_deep_empty_arms = s.try_each_variant(|variant| {
55 if is_newtype_variant(variant) {
56 let ident = &variant.bindings()[0].binding;
57 return Ok(quote! {
58 ::relay_protocol::Empty::is_deep_empty(#ident)
59 });
60 }
61
62 let mut cond = quote!(true);
63 let mut is_tuple_struct = false;
64 for (index, bi) in variant.bindings().iter().enumerate() {
65 let field_attrs = parse_field_attributes(index, bi.ast(), &mut is_tuple_struct)?;
66 let ident = &bi.binding;
67 let skip_serialization_attr = field_attrs.skip_serialization.as_tokens();
68
69 if field_attrs.additional_properties {
70 cond = quote! {
71 #cond && #bi.values().all(|v| v.skip_serialization(#skip_serialization_attr))
72 };
73 } else if field_attrs.flatten {
74 cond = quote! {
75 #cond && ::relay_protocol::Empty::is_deep_empty(#ident)
76 };
77 } else {
78 cond = quote! {
79 #cond && #ident.skip_serialization(#skip_serialization_attr)
80 };
81 }
82 }
83
84 Ok(cond)
85 })?;
86
87 Ok(s.gen_impl(quote! {
88 #[automatically_derived]
89 gen impl ::relay_protocol::Empty for @Self {
90 fn is_empty(&self) -> bool {
91 match *self {
92 #is_empty_arms
93 }
94 }
95
96 fn is_deep_empty(&self) -> bool {
97 match *self {
98 #is_deep_empty_arms
99 }
100 }
101 }
102 }))
103}
104
105fn derive_to_value(s: synstructure::Structure<'_>) -> syn::Result<TokenStream> {
106 derive_metastructure(s, Trait::To)
107}
108
109fn derive_from_value(s: synstructure::Structure<'_>) -> syn::Result<TokenStream> {
110 derive_metastructure(s, Trait::From)
111}
112
113fn derive_newtype_metastructure(
114 s: &synstructure::Structure<'_>,
115 t: Trait,
116) -> syn::Result<TokenStream> {
117 let type_attrs = parse_type_attributes(s)?;
118 if type_attrs.tag_key.is_some() {
119 panic!("tag_key not supported on structs");
120 }
121
122 let field_attrs = parse_field_attributes(0, s.variants()[0].bindings()[0].ast(), &mut true)?;
123 let skip_serialization_attr = field_attrs.skip_serialization.as_tokens();
124
125 let name = &s.ast().ident;
126
127 Ok(match t {
128 Trait::From => s.gen_impl(quote! {
129 #[automatically_derived]
130 gen impl ::relay_protocol::FromValue for @Self {
131 fn from_value(
132 __value: ::relay_protocol::Annotated<::relay_protocol::Value>,
133 ) -> ::relay_protocol::Annotated<Self> {
134 match ::relay_protocol::FromValue::from_value(__value) {
135 Annotated(Some(__value), __meta) => Annotated(Some(#name(__value)), __meta),
136 Annotated(None, __meta) => Annotated(None, __meta),
137 }
138 }
139 }
140 }),
141 Trait::To => s.gen_impl(quote! {
142 #[automatically_derived]
143 gen impl ::relay_protocol::IntoValue for @Self {
144 fn into_value(self) -> ::relay_protocol::Value {
145 ::relay_protocol::IntoValue::into_value(self.0)
146 }
147
148 fn serialize_payload<S>(&self, __serializer: S, __behavior: ::relay_protocol::SkipSerialization) -> Result<S::Ok, S::Error>
149 where
150 Self: Sized,
151 S: ::serde::ser::Serializer
152 {
153 ::relay_protocol::IntoValue::serialize_payload(&self.0, __serializer, #skip_serialization_attr)
154 }
155
156 fn extract_child_meta(&self) -> ::relay_protocol::MetaMap
157 where
158 Self: Sized,
159 {
160 ::relay_protocol::IntoValue::extract_child_meta(&self.0)
161 }
162 }
163 }),
164 })
165}
166
167fn derive_enum_metastructure(
168 s: &synstructure::Structure<'_>,
169 t: Trait,
170) -> syn::Result<TokenStream> {
171 let type_attrs = parse_type_attributes(s)?;
172
173 let type_name = &s.ast().ident;
174 let tag_key_str = LitStr::new(
175 &type_attrs.tag_key.unwrap_or_else(|| "type".to_string()),
176 Span::call_site(),
177 );
178
179 let mut from_value_body = TokenStream::new();
180 let mut to_value_body = TokenStream::new();
181 let mut serialize_body = TokenStream::new();
182 let mut extract_child_meta_body = TokenStream::new();
183
184 for variant in s.variants() {
185 let variant_attrs = parse_variant_attributes(variant.ast().attrs)?;
186 let variant_name = &variant.ast().ident;
187 let tag = variant_attrs
188 .tag_override
189 .unwrap_or_else(|| variant_name.to_string().to_lowercase());
190
191 if !variant_attrs.fallback_variant {
192 let tag = LitStr::new(&tag, Span::call_site());
193 (quote! {
194 Some(#tag) => {
195 ::relay_protocol::FromValue::from_value(::relay_protocol::Annotated(Some(::relay_protocol::Value::Object(__object)), __meta))
196 .map_value(#type_name::#variant_name)
197 }
198 }).to_tokens(&mut from_value_body);
199 (quote! {
200 #type_name::#variant_name(__value) => {
201 let mut __rv = ::relay_protocol::IntoValue::into_value(__value);
202 if let ::relay_protocol::Value::Object(ref mut __object) = __rv {
203 __object.insert(#tag_key_str.to_string(), Annotated::new(::relay_protocol::Value::String(#tag.to_string())));
204 }
205 __rv
206 }
207 }).to_tokens(&mut to_value_body);
208 (quote! {
209 #type_name::#variant_name(ref __value) => {
210 let mut __map_ser = ::serde::Serializer::serialize_map(__serializer, None)?;
211 ::relay_protocol::IntoValue::serialize_payload(__value, ::serde::__private::ser::FlatMapSerializer(&mut __map_ser), __behavior)?;
212 ::serde::ser::SerializeMap::serialize_key(&mut __map_ser, #tag_key_str)?;
213 ::serde::ser::SerializeMap::serialize_value(&mut __map_ser, #tag)?;
214 ::serde::ser::SerializeMap::end(__map_ser)
215 }
216 }).to_tokens(&mut serialize_body);
217 } else {
218 (quote! {
219 _ => {
220 if let Some(__type) = __type {
221 __object.insert(#tag_key_str.to_string(), __type);
222 }
223 ::relay_protocol::Annotated(Some(#type_name::#variant_name(__object)), __meta)
224 }
225 })
226 .to_tokens(&mut from_value_body);
227 (quote! {
228 #type_name::#variant_name(__value) => {
229 ::relay_protocol::IntoValue::into_value(__value)
230 }
231 })
232 .to_tokens(&mut to_value_body);
233 (quote! {
234 #type_name::#variant_name(ref __value) => {
235 ::relay_protocol::IntoValue::serialize_payload(__value, __serializer, __behavior)
236 }
237 })
238 .to_tokens(&mut serialize_body);
239 }
240
241 (quote! {
242 #type_name::#variant_name(ref __value) => {
243 ::relay_protocol::IntoValue::extract_child_meta(__value)
244 }
245 })
246 .to_tokens(&mut extract_child_meta_body);
247 }
248
249 Ok(match t {
250 Trait::From => {
251 s.gen_impl(quote! {
252 #[automatically_derived]
253 gen impl ::relay_protocol::FromValue for @Self {
254 fn from_value(
255 __value: ::relay_protocol::Annotated<::relay_protocol::Value>,
256 ) -> ::relay_protocol::Annotated<Self> {
257 match ::relay_protocol::Object::<::relay_protocol::Value>::from_value(__value) {
258 ::relay_protocol::Annotated(Some(mut __object), __meta) => {
259 let __type = __object.remove(#tag_key_str);
260 match __type.as_ref().and_then(|__type| __type.0.as_ref()).and_then(Value::as_str) {
261 #from_value_body
262 }
263 }
264 ::relay_protocol::Annotated(None, __meta) => ::relay_protocol::Annotated(None, __meta)
265 }
266 }
267 }
268 })
269 }
270 Trait::To => {
271 s.gen_impl(quote! {
272 #[automatically_derived]
273 gen impl ::relay_protocol::IntoValue for @Self {
274 fn into_value(self) -> ::relay_protocol::Value {
275 match self {
276 #to_value_body
277 }
278 }
279
280 fn serialize_payload<S>(&self, __serializer: S, __behavior: ::relay_protocol::SkipSerialization) -> Result<S::Ok, S::Error>
281 where
282 S: ::serde::ser::Serializer
283 {
284 match *self {
285 #serialize_body
286 }
287 }
288
289 fn extract_child_meta(&self) -> ::relay_protocol::MetaMap
290 where
291 Self: Sized,
292 {
293 match *self {
294 #extract_child_meta_body
295 }
296 }
297 }
298 })
299 }
300 })
301}
302
303fn derive_metastructure(mut s: synstructure::Structure<'_>, t: Trait) -> syn::Result<TokenStream> {
304 if is_newtype(&s) {
305 return derive_newtype_metastructure(&s, t);
306 }
307
308 if let Data::Enum(_) = s.ast().data {
309 return derive_enum_metastructure(&s, t);
310 }
311
312 let _ = s.add_bounds(synstructure::AddBounds::Generics);
313
314 let variants = s.variants();
315 if variants.len() != 1 {
316 panic!("Can only derive structs");
317 }
318
319 let mut variant = variants[0].clone();
320 for binding in variant.bindings_mut() {
321 binding.style = synstructure::BindStyle::MoveMut;
322 }
323
324 let mut from_value_body = TokenStream::new();
325 let mut to_value_body = TokenStream::new();
326 let mut serialize_body = TokenStream::new();
327 let mut extract_child_meta_body = TokenStream::new();
328
329 let type_attrs = parse_type_attributes(&s)?;
330 if type_attrs.tag_key.is_some() {
331 panic!("tag_key not supported on structs");
332 }
333
334 let mut is_tuple_struct = false;
335
336 for (index, bi) in variant.bindings().iter().enumerate() {
337 let field_attrs = parse_field_attributes(index, bi.ast(), &mut is_tuple_struct)?;
338 let field_name = field_attrs.field_name.clone();
339
340 let skip_serialization_attr = field_attrs.skip_serialization.as_tokens();
341
342 if field_attrs.additional_properties {
343 if is_tuple_struct {
344 panic!("additional_properties not allowed in tuple struct");
345 }
346
347 (quote! {
348 let #bi = ::std::mem::take(__obj).into_iter().map(|(__key, __value)| (__key, ::relay_protocol::FromValue::from_value(__value))).collect();
349 }).to_tokens(&mut from_value_body);
350
351 (quote! {
352 __map.extend(#bi.into_iter().map(|(__key, __value)| (
353 __key,
354 Annotated::map_value(__value, ::relay_protocol::IntoValue::into_value)
355 )));
356 })
357 .to_tokens(&mut to_value_body);
358
359 (quote! {
360 for (__key, __value) in #bi.iter() {
361 if !__value.skip_serialization(#skip_serialization_attr) {
362 ::serde::ser::SerializeMap::serialize_key(&mut __map_serializer, __key)?;
363 ::serde::ser::SerializeMap::serialize_value(&mut __map_serializer, &::relay_protocol::SerializePayload(__value, #skip_serialization_attr))?;
364 }
365 }
366 })
367 .to_tokens(&mut serialize_body);
368
369 (quote! {
370 for (__key, __value) in #bi.iter() {
371 let __inner_tree = ::relay_protocol::IntoValue::extract_meta_tree(__value);
372 if !__inner_tree.is_empty() {
373 __child_meta.insert(__key.to_string(), __inner_tree);
374 }
375 }
376 })
377 .to_tokens(&mut extract_child_meta_body);
378 } else if field_attrs.flatten {
379 if is_tuple_struct {
380 panic!("flatten not allowed in tuple struct");
381 }
382
383 (quote! {
384 let #bi = ::relay_protocol::FromObjectRef::from_object_ref(__obj);
385 })
386 .to_tokens(&mut from_value_body);
387
388 (quote! {
389 ::relay_protocol::IntoObjectRef::into_object_ref(#bi, __map);
390 })
391 .to_tokens(&mut to_value_body);
392
393 (quote! {
394 ::relay_protocol::IntoValue::serialize_payload(#bi, ::serde::__private::ser::FlatMapSerializer(&mut __map_serializer), __behavior)?;
395 }).to_tokens(&mut serialize_body);
396
397 (quote! {
398 __child_meta.extend(::relay_protocol::IntoValue::extract_child_meta(#bi));
399 })
400 .to_tokens(&mut extract_child_meta_body);
401 } else {
402 if is_tuple_struct {
403 (quote! {
404 let #bi = __arr.next();
405 })
406 .to_tokens(&mut from_value_body);
407 } else {
408 (quote! {
409 let #bi = __obj.remove(#field_name);
410 })
411 .to_tokens(&mut from_value_body);
412
413 for legacy_alias in &field_attrs.legacy_aliases {
414 let legacy_field_name = LitStr::new(legacy_alias, Span::call_site());
415 (quote! {
416 let #bi = #bi.or(__obj.remove(#legacy_field_name));
417 })
418 .to_tokens(&mut from_value_body);
419 }
420 }
421
422 (quote! {
423 let #bi = ::relay_protocol::FromValue::from_value(#bi.unwrap_or_else(|| ::relay_protocol::Annotated(None, ::relay_protocol::Meta::default())));
424 }).to_tokens(&mut from_value_body);
425
426 if is_tuple_struct {
427 (quote! {
428 __arr.push(Annotated::map_value(#bi, ::relay_protocol::IntoValue::into_value));
429 })
430 .to_tokens(&mut to_value_body);
431 (quote! {
432 if !#bi.skip_serialization(#skip_serialization_attr) {
433 ::serde::ser::SerializeSeq::serialize_element(&mut __seq_serializer, &::relay_protocol::SerializePayload(#bi, #skip_serialization_attr))?;
434 }
435 }).to_tokens(&mut serialize_body);
436 } else {
437 (quote! {
438 __map.insert(#field_name.to_string(), Annotated::map_value(#bi, ::relay_protocol::IntoValue::into_value));
439 }).to_tokens(&mut to_value_body);
440 (quote! {
441 if !#bi.skip_serialization(#skip_serialization_attr) {
442 ::serde::ser::SerializeMap::serialize_key(&mut __map_serializer, #field_name)?;
443 ::serde::ser::SerializeMap::serialize_value(&mut __map_serializer, &::relay_protocol::SerializePayload(#bi, #skip_serialization_attr))?;
444 }
445 }).to_tokens(&mut serialize_body);
446 }
447
448 (quote! {
449 let __inner_tree = ::relay_protocol::IntoValue::extract_meta_tree(#bi);
450 if !__inner_tree.is_empty() {
451 __child_meta.insert(#field_name.to_string(), __inner_tree);
452 }
453 })
454 .to_tokens(&mut extract_child_meta_body);
455 }
456 }
457
458 let ast = s.ast();
459 let expectation = LitStr::new(&ast.ident.to_string().to_lowercase(), Span::call_site());
460 let mut variant = variant.clone();
461 for binding in variant.bindings_mut() {
462 binding.style = synstructure::BindStyle::Move;
463 }
464 let to_value_pat = variant.pat();
465 let to_structure_assemble_pat = variant.pat();
466 for binding in variant.bindings_mut() {
467 binding.style = synstructure::BindStyle::Ref;
468 }
469 let serialize_pat = variant.pat();
470
471 Ok(match t {
472 Trait::From => {
473 let bindings_count = variant.bindings().len();
474 if is_tuple_struct {
475 s.gen_impl(quote! {
476 #[automatically_derived]
477 gen impl ::relay_protocol::FromValue for @Self {
478 fn from_value(
479 __value: ::relay_protocol::Annotated<::relay_protocol::Value>,
480 ) -> ::relay_protocol::Annotated<Self> {
481 match __value {
482 ::relay_protocol::Annotated(Some(::relay_protocol::Value::Array(mut __arr)), mut __meta) => {
483 if __arr.len() != #bindings_count {
484 __meta.add_error(Error::expected(concat!("a ", stringify!(#bindings_count), "-tuple")));
485 __meta.set_original_value(Some(__arr));
486 Annotated(None, __meta)
487 } else {
488 let mut __arr = __arr.into_iter();
489 #from_value_body;
490 ::relay_protocol::Annotated(Some(#to_structure_assemble_pat), __meta)
491 }
492 }
493 ::relay_protocol::Annotated(None, __meta) => ::relay_protocol::Annotated(None, __meta),
494 ::relay_protocol::Annotated(Some(__value), mut __meta) => {
495 __meta.add_error(::relay_protocol::Error::expected(#expectation));
496 __meta.set_original_value(Some(__value));
497 ::relay_protocol::Annotated(None, __meta)
498 }
499 }
500 }
501 }
502 })
503 } else {
504 s.gen_impl(quote! {
505 #[automatically_derived]
506 gen impl ::relay_protocol::FromValue for @Self {
507 fn from_value(
508 mut __value: ::relay_protocol::Annotated<::relay_protocol::Value>,
509 ) -> ::relay_protocol::Annotated<Self> {
510 match __value {
511 ::relay_protocol::Annotated(Some(::relay_protocol::Value::Object(ref mut __obj)), __meta) => {
512 #from_value_body;
513 ::relay_protocol::Annotated(Some(#to_structure_assemble_pat), __meta)
514 },
515 ::relay_protocol::Annotated(None, __meta) => ::relay_protocol::Annotated(None, __meta),
516 ::relay_protocol::Annotated(Some(__value), mut __meta) => {
517 __meta.add_error(::relay_protocol::Error::expected(#expectation));
518 __meta.set_original_value(Some(__value));
519 ::relay_protocol::Annotated(None, __meta)
520 }
521 }
522 }
523 }
524
525 #[automatically_derived]
526 gen impl ::relay_protocol::FromObjectRef for @Self {
527 fn from_object_ref(__obj: &mut relay_protocol::Object<::relay_protocol::Value>) -> Self {
528 #from_value_body;
529 #to_structure_assemble_pat
530 }
531 }
532 })
533 }
534 }
535 Trait::To => {
536 let into_value = if is_tuple_struct {
537 quote! {
538 let mut __arr = ::relay_protocol::Array::new();
539 let #to_value_pat = self;
540 #to_value_body;
541 ::relay_protocol::Value::Array(__arr)
542 }
543 } else {
544 quote! {
545 let mut __map_ret = ::relay_protocol::Object::new();
546 let #to_value_pat = self;
547 let mut __map = &mut __map_ret;
548 #to_value_body;
549 ::relay_protocol::Value::Object(__map_ret)
550 }
551 };
552
553 let serialize_payload = if is_tuple_struct {
554 quote! {
555 let mut __seq_serializer = ::serde::ser::Serializer::serialize_seq(__serializer, None)?;
556 #serialize_body;
557 ::serde::ser::SerializeSeq::end(__seq_serializer)
558 }
559 } else {
560 quote! {
561 let mut __map_serializer = ::serde::ser::Serializer::serialize_map(__serializer, None)?;
562 #serialize_body;
563 ::serde::ser::SerializeMap::end(__map_serializer)
564 }
565 };
566
567 let into_value = s.gen_impl(quote! {
568 #[automatically_derived]
569 gen impl ::relay_protocol::IntoValue for @Self {
570 fn into_value(self) -> ::relay_protocol::Value {
571 #into_value
572 }
573
574 fn serialize_payload<S>(&self, __serializer: S, __behavior: ::relay_protocol::SkipSerialization) -> Result<S::Ok, S::Error>
575 where
576 Self: Sized,
577 S: ::serde::ser::Serializer
578 {
579 let #serialize_pat = *self;
580 #serialize_payload
581 }
582
583 fn extract_child_meta(&self) -> ::relay_protocol::MetaMap
584 where
585 Self: Sized,
586 {
587 let mut __child_meta = ::relay_protocol::MetaMap::new();
588 let #serialize_pat = *self;
589 #extract_child_meta_body;
590 __child_meta
591 }
592 }
593 });
594
595 let into_object_ref = (!is_tuple_struct).then(|| s.gen_impl(quote! {
596 #[automatically_derived]
597 gen impl ::relay_protocol::IntoObjectRef for @Self {
598 fn into_object_ref(self, __map: &mut ::relay_protocol::Object<::relay_protocol::Value>) {
599 let #to_value_pat = self;
600 #to_value_body;
601 }
602 }
603 }));
604
605 quote! {
606 #into_value
607 #into_object_ref
608 }
609 }
610 })
611}
612
613#[derive(Default)]
614struct TypeAttrs {
615 tag_key: Option<String>,
616}
617
618fn parse_type_attributes(s: &synstructure::Structure<'_>) -> syn::Result<TypeAttrs> {
619 let mut rv = TypeAttrs::default();
620
621 for attr in &s.ast().attrs {
622 if !attr.path().is_ident("metastructure") {
623 continue;
624 }
625
626 attr.parse_nested_meta(|meta| {
627 let ident = meta.path.require_ident()?;
628
629 if ident == "tag_key" {
630 let s = meta.value()?.parse::<LitStr>()?;
631 rv.tag_key = Some(s.value());
632 } else {
633 let _ = meta.value()?.parse::<Lit>()?;
635 }
636
637 Ok(())
638 })?;
639 }
640
641 if rv.tag_key.is_some() && s.variants().len() == 1 {
642 return Err(Error::new(
644 s.ast().span(),
645 "tag_key not supported on structs",
646 ));
647 }
648
649 Ok(rv)
650}
651
652#[derive(Default)]
653struct FieldAttrs {
654 additional_properties: bool,
655 field_name: String,
656 flatten: bool,
657 legacy_aliases: Vec<String>,
658 skip_serialization: SkipSerialization,
659}
660
661#[derive(Copy, Clone, Default)]
662enum SkipSerialization {
663 #[default]
664 Never,
665 Null(bool),
666 Empty(bool),
667}
668
669impl SkipSerialization {
670 fn as_tokens(self) -> TokenStream {
671 match self {
672 SkipSerialization::Never => quote!(::relay_protocol::SkipSerialization::Never),
673 SkipSerialization::Null(deep) => {
674 quote!(::relay_protocol::SkipSerialization::Null(#deep))
675 }
676 SkipSerialization::Empty(deep) => {
677 quote!(::relay_protocol::SkipSerialization::Empty(#deep))
678 }
679 }
680 }
681}
682
683impl FromStr for SkipSerialization {
684 type Err = ();
685
686 fn from_str(s: &str) -> Result<Self, ()> {
687 Ok(match s {
688 "never" => SkipSerialization::Never,
689 "null" => SkipSerialization::Null(false),
690 "null_deep" => SkipSerialization::Null(true),
691 "empty" => SkipSerialization::Empty(false),
692 "empty_deep" => SkipSerialization::Empty(true),
693 _ => return Err(()),
694 })
695 }
696}
697
698fn parse_field_attributes(
699 index: usize,
700 bi_ast: &syn::Field,
701 is_tuple_struct: &mut bool,
702) -> syn::Result<FieldAttrs> {
703 if bi_ast.ident.is_none() {
704 *is_tuple_struct = true;
705 } else if *is_tuple_struct {
706 panic!("invalid tuple struct");
707 }
708
709 let mut rv = FieldAttrs::default();
710 if !*is_tuple_struct {
711 rv.skip_serialization = SkipSerialization::Null(false);
712 }
713 rv.field_name = bi_ast
714 .ident
715 .as_ref()
716 .map(ToString::to_string)
717 .unwrap_or_else(|| index.to_string());
718
719 for attr in &bi_ast.attrs {
720 if !attr.path().is_ident("metastructure") {
721 continue;
722 }
723
724 attr.parse_nested_meta(|meta| {
725 let ident = meta.path.require_ident()?;
726
727 if ident == "additional_properties" {
728 rv.additional_properties = true;
729 } else if ident == "omit_from_schema" {
730 } else if ident == "field" {
732 rv.field_name = meta.value()?.parse::<LitStr>()?.value();
733 } else if ident == "flatten" {
734 rv.flatten = true;
735 } else if ident == "legacy_alias" {
736 rv.legacy_aliases
737 .push(meta.value()?.parse::<LitStr>()?.value());
738 } else if ident == "skip_serialization" {
739 rv.skip_serialization = meta
740 .value()?
741 .parse::<LitStr>()?
742 .value()
743 .parse()
744 .map_err(|_| meta.error("Unknown value"))?;
745 } else {
746 let _ = meta.value()?.parse::<Lit>()?;
748 }
749
750 Ok(())
751 })?;
752 }
753
754 Ok(rv)
755}
756
757#[derive(Default)]
758struct VariantAttrs {
759 omit_from_schema: bool,
760 tag_override: Option<String>,
761 fallback_variant: bool,
762}
763
764fn parse_variant_attributes(attrs: &[syn::Attribute]) -> syn::Result<VariantAttrs> {
765 let mut rv = VariantAttrs::default();
766 for attr in attrs {
767 if !attr.path().is_ident("metastructure") {
768 continue;
769 }
770
771 attr.parse_nested_meta(|meta| {
772 let ident = meta.path.require_ident()?;
773
774 if ident == "fallback_variant" {
775 rv.tag_override = None;
776 rv.fallback_variant = true;
777 } else if ident == "omit_from_schema" {
778 rv.omit_from_schema = true;
779 } else if ident == "tag" {
780 rv.tag_override = Some(meta.value()?.parse::<LitStr>()?.value());
781 } else {
782 let _ = meta.value()?.parse::<Lit>()?;
784 }
785
786 Ok(())
787 })?;
788 }
789
790 Ok(rv)
791}
792
793fn is_newtype_variant(variant: &synstructure::VariantInfo) -> bool {
794 variant.bindings().len() == 1 && variant.bindings()[0].ast().ident.is_none()
795}
796
797fn is_newtype(s: &synstructure::Structure<'_>) -> bool {
798 if s.variants().len() != 1 {
799 return false;
801 }
802
803 if s.variants()[0].bindings().len() != 1 {
804 return false;
808 }
809
810 if s.variants()[0].bindings()[0].ast().ident.is_some() {
811 return false;
814 }
815
816 true
817}