swc_macros_common/
binder.rs

1//! # Example
2//!
3//! `_binded_a`, `_binded_b` and `_binded_0` in below example are
4//! `BindedField`.
5//!
6//! ```rust
7//! struct S {
8//!     a: u8,
9//!     b: u16,
10//! }
11//! let s = S { a: 0, b: 0 };
12//! match s {
13//!     S {
14//!         a: _binded_a,
15//!         b: _binded_b,
16//!     } => {}
17//! }
18//! enum E {
19//!     V1 { a: u8 },
20//!     V2(u16),
21//!     V3,
22//! }
23//! let e = E::V1 { a: 0 };
24//! match e {
25//!     E::V1 { a: _binded_a } => {}
26//!     E::V2(_binded_0) => {}
27//!     E::V3 => {}
28//! }
29//! ```
30//!
31//!
32//! -----
33//!
34//! Adopted from `synstructure`.
35use 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/// Used to bind whole struct or enum.
46#[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    ///
55    /// - `attrs`: Attributes of the type.
56    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/// Variant.
82#[derive(Debug, Clone)]
83pub struct VariantBinder<'a> {
84    /// None for struct.
85    enum_name: Option<&'a Ident>,
86    /// Name of variant.
87    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    /// `EnumName::VariantName` for enum, and `StructName` for struct.
120    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    ///
132    ///  - `prefix`: prefix of field binding.
133    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                // EnumName::VariantName
144                let pat = Pat::Path(PatPath {
145                    qself: None,
146                    path,
147                    attrs: Default::default(),
148                });
149
150                // Unit struct does not have any field to bind
151                (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                // EnumName::VariantName { fields }
201                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                // TODO
216                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 = Ident::new(&format!("{prefix}{idx}"), def_site());
228
229                            bindings.push(BindedField {
230                                idx,
231                                binded_ident: binded_ident.clone(),
232                                field: f,
233                            });
234
235                            Pat::Ident(PatIdent {
236                                by_ref,
237                                mutability,
238                                ident: binded_ident,
239                                subpat: None,
240                                attrs: Default::default(),
241                            })
242                        })
243                    })
244                    .collect();
245                // EnumName::VariantName ( fields )
246                let pat = Pat::TupleStruct(PatTupleStruct {
247                    attrs: Default::default(),
248                    qself: None,
249                    path,
250                    paren_token,
251                    elems: pats,
252                });
253                (pat, bindings)
254            }
255        };
256
257        // if we don't need to move fields, we should match on reference to make tuple
258        // work.
259
260        // let pat = match by_ref {
261        //     Some(ref_token) => Pat::Ref(PatRef {
262        //         pat: box pat,
263        //         and_token: ref_token.0.as_token(),
264        //         mutability,
265        //     }),
266        //     None => pat,
267        // };
268
269        (pat, bindings)
270    }
271}
272
273/// Binded field. Note that this struct acts like a binded variable for
274/// `quote!`.
275#[derive(Debug, Clone)]
276pub struct BindedField<'a> {
277    binded_ident: Ident,
278    idx: usize,
279    field: &'a Field,
280}
281
282impl BindedField<'_> {
283    pub const fn idx(&self) -> usize {
284        self.idx
285    }
286
287    /// Name of field binding.
288    pub const fn name(&self) -> &Ident {
289        &self.binded_ident
290    }
291
292    pub const fn field(&self) -> &Field {
293        self.field
294    }
295}
296
297impl ToTokens for BindedField<'_> {
298    fn to_tokens(&self, t: &mut TokenStream) {
299        self.binded_ident.to_tokens(t)
300    }
301}