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 =
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                // EnumName::VariantName ( fields )
247                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        // if we don't need to move fields, we should match on reference to make tuple
259        // work.
260
261        // let pat = match by_ref {
262        //     Some(ref_token) => Pat::Ref(PatRef {
263        //         pat: box pat,
264        //         and_token: ref_token.0.as_token(),
265        //         mutability,
266        //     }),
267        //     None => pat,
268        // };
269
270        (pat, bindings)
271    }
272}
273
274/// Binded field. Note that this struct acts like a binded variable for
275/// `quote!`.
276#[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    /// Name of field binding.
289    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}