1use proc_macro2::TokenStream;
36use quote::ToTokens;
37use syn::{
38 punctuated::Pair,
39 token::{Mut, Ref},
40 *,
41};
42
43use crate::{def_site, is_attr_name, syn_ext::PairExt};
44
45#[derive(Debug, Clone)]
47pub struct Binder<'a> {
48 ident: &'a Ident,
49 body: &'a Data,
50 attrs: &'a [Attribute],
51}
52
53impl<'a> Binder<'a> {
54 pub const fn new(ident: &'a Ident, body: &'a Data, attrs: &'a [Attribute]) -> Self {
57 Binder { ident, body, attrs }
58 }
59
60 pub fn new_from(input: &'a DeriveInput) -> Self {
61 Self::new(&input.ident, &input.data, &input.attrs)
62 }
63
64 pub fn variants(&self) -> Vec<VariantBinder<'a>> {
65 match *self.body {
66 Data::Enum(DataEnum { ref variants, .. }) => {
67 let enum_name = &self.ident;
68 variants
69 .iter()
70 .map(|v| VariantBinder::new(Some(enum_name), &v.ident, &v.fields, &v.attrs))
71 .collect()
72 }
73 Data::Struct(DataStruct { ref fields, .. }) => {
74 vec![VariantBinder::new(None, self.ident, fields, self.attrs)]
75 }
76 Data::Union(_) => unimplemented!("Binder for union type"),
77 }
78 }
79}
80
81#[derive(Debug, Clone)]
83pub struct VariantBinder<'a> {
84 enum_name: Option<&'a Ident>,
86 name: &'a Ident,
88 data: &'a Fields,
89 attrs: &'a [Attribute],
90}
91
92impl<'a> VariantBinder<'a> {
93 pub const fn new(
94 enum_name: Option<&'a Ident>,
95 name: &'a Ident,
96 data: &'a Fields,
97 attrs: &'a [Attribute],
98 ) -> Self {
99 VariantBinder {
100 enum_name,
101 name,
102 data,
103 attrs,
104 }
105 }
106
107 pub const fn variant_name(&self) -> &Ident {
108 self.name
109 }
110
111 pub const fn data(&self) -> &Fields {
112 self.data
113 }
114
115 pub const fn attrs(&self) -> &[Attribute] {
116 self.attrs
117 }
118
119 pub fn qual_path(&self) -> Path {
121 match self.enum_name {
122 Some(enum_name) => {
123 let vn = &self.name;
124
125 parse_quote!(#enum_name::#vn)
126 }
127 None => self.name.clone().into(),
128 }
129 }
130
131 pub fn bind(
134 &self,
135 prefix: &str,
136 by_ref: Option<Ref>,
137 mutability: Option<Mut>,
138 ) -> (Pat, Vec<BindedField<'a>>) {
139 let path = self.qual_path();
140
141 let (pat, bindings) = match *self.data {
142 Fields::Unit => {
143 let pat = Pat::Path(PatPath {
145 qself: None,
146 path,
147 attrs: Default::default(),
148 });
149
150 (pat, Vec::new())
152 }
153 Fields::Named(FieldsNamed {
154 named: ref fields,
155 brace_token,
156 }) => {
157 let mut bindings = Vec::new();
158
159 let fields = fields
160 .pairs()
161 .map(|e| {
162 let (t, p) = e.into_tuple();
163 Pair::new(t, p.cloned())
164 })
165 .enumerate()
166 .map(|(idx, f)| {
167 f.map_item(|f| {
168 let ident = f
169 .ident
170 .clone()
171 .expect("field of struct-like variants should have name");
172
173 let binded_ident =
174 Ident::new(&format!("{}{}", prefix, ident), ident.span());
175 bindings.push(BindedField {
176 idx,
177 binded_ident: binded_ident.clone(),
178 field: f,
179 });
180 FieldPat {
181 attrs: f
182 .attrs
183 .iter()
184 .filter(|attr| is_attr_name(attr, "cfg"))
185 .cloned()
186 .collect(),
187 colon_token: f.colon_token,
188 member: Member::Named(ident),
189 pat: Box::new(Pat::Ident(PatIdent {
190 by_ref,
191 mutability,
192 ident: binded_ident,
193 subpat: None,
194 attrs: Default::default(),
195 })),
196 }
197 })
198 })
199 .collect();
200 let pat = Pat::Struct(PatStruct {
202 attrs: Default::default(),
203 qself: None,
204 path,
205 brace_token,
206 fields,
207 rest: None,
208 });
209 (pat, bindings)
210 }
211 Fields::Unnamed(FieldsUnnamed {
212 unnamed: ref fields,
213 paren_token,
214 }) => {
215 let mut bindings = Vec::new();
217
218 let pats = fields
219 .pairs()
220 .map(|e| {
221 let (t, p) = e.into_tuple();
222 Pair::new(t, p.cloned())
223 })
224 .enumerate()
225 .map(|(idx, f)| {
226 f.map_item(|f| {
227 let binded_ident =
228 Ident::new(&format!("{}{}", prefix, idx), def_site());
229
230 bindings.push(BindedField {
231 idx,
232 binded_ident: binded_ident.clone(),
233 field: f,
234 });
235
236 Pat::Ident(PatIdent {
237 by_ref,
238 mutability,
239 ident: binded_ident,
240 subpat: None,
241 attrs: Default::default(),
242 })
243 })
244 })
245 .collect();
246 let pat = Pat::TupleStruct(PatTupleStruct {
248 attrs: Default::default(),
249 qself: None,
250 path,
251 paren_token,
252 elems: pats,
253 });
254 (pat, bindings)
255 }
256 };
257
258 (pat, bindings)
271 }
272}
273
274#[derive(Debug, Clone)]
277pub struct BindedField<'a> {
278 binded_ident: Ident,
279 idx: usize,
280 field: &'a Field,
281}
282
283impl BindedField<'_> {
284 pub const fn idx(&self) -> usize {
285 self.idx
286 }
287
288 pub const fn name(&self) -> &Ident {
290 &self.binded_ident
291 }
292
293 pub const fn field(&self) -> &Field {
294 self.field
295 }
296}
297
298impl ToTokens for BindedField<'_> {
299 fn to_tokens(&self, t: &mut TokenStream) {
300 self.binded_ident.to_tokens(t)
301 }
302}