1use proc_macro2::{Span, TokenStream};
10use quote::ToTokens;
11use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Ident, Index, Type, Visibility};
12
13pub(crate) trait DataExt {
14 fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>;
23
24 fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>>;
25
26 fn tag(&self) -> Option<Ident>;
27}
28
29impl DataExt for Data {
30 fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
31 match self {
32 Data::Struct(strc) => strc.fields(),
33 Data::Enum(enm) => enm.fields(),
34 Data::Union(un) => un.fields(),
35 }
36 }
37
38 fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>> {
39 match self {
40 Data::Struct(strc) => strc.variants(),
41 Data::Enum(enm) => enm.variants(),
42 Data::Union(un) => un.variants(),
43 }
44 }
45
46 fn tag(&self) -> Option<Ident> {
47 match self {
48 Data::Struct(strc) => strc.tag(),
49 Data::Enum(enm) => enm.tag(),
50 Data::Union(un) => un.tag(),
51 }
52 }
53}
54
55impl DataExt for DataStruct {
56 fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
57 map_fields(&self.fields)
58 }
59
60 fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>> {
61 vec![self.fields()]
62 }
63
64 fn tag(&self) -> Option<Ident> {
65 None
66 }
67}
68
69impl DataExt for DataEnum {
70 fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
71 map_fields(self.variants.iter().flat_map(|var| &var.fields))
72 }
73
74 fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>> {
75 self.variants.iter().map(|var| map_fields(&var.fields)).collect()
76 }
77
78 fn tag(&self) -> Option<Ident> {
79 Some(Ident::new("___ZerocopyTag", Span::call_site()))
80 }
81}
82
83impl DataExt for DataUnion {
84 fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
85 map_fields(&self.fields.named)
86 }
87
88 fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>> {
89 vec![self.fields()]
90 }
91
92 fn tag(&self) -> Option<Ident> {
93 None
94 }
95}
96
97fn map_fields<'a>(
98 fields: impl 'a + IntoIterator<Item = &'a Field>,
99) -> Vec<(&'a Visibility, TokenStream, &'a Type)> {
100 fields
101 .into_iter()
102 .enumerate()
103 .map(|(idx, f)| {
104 (
105 &f.vis,
106 f.ident
107 .as_ref()
108 .map(ToTokens::to_token_stream)
109 .unwrap_or_else(|| Index::from(idx).to_token_stream()),
110 &f.ty,
111 )
112 })
113 .collect()
114}