Skip to main content

impl_tools_lib/
anon.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! The `impl_anon!` macro
7
8use crate::fields::{Field, Fields, FieldsNamed, FieldsUnnamed, StructStyle};
9use crate::scope::{Scope, ScopeItem};
10use crate::{IdentFormatter, error_on_attrs};
11use proc_macro2::{Span, TokenStream};
12use quote::{ToTokens, TokenStreamExt, quote};
13use syn::token::{Brace, Colon, Comma, Eq, Paren, Semi};
14use syn::{Attribute, GenericParam, Generics, Ident, ItemImpl, Member, Token, Type, TypePath};
15use syn::{parse_quote, punctuated::Punctuated, spanned::Spanned};
16
17/// A field of a [`Anon`]
18#[derive(Debug)]
19pub struct AnonField {
20    /// Field attributes
21    pub attrs: Vec<Attribute>,
22    /// Field visibility
23    pub vis: syn::Visibility,
24    /// Field identifier (regular structs only, and optional even there)
25    pub ident: Option<Ident>,
26    /// Separator between identifier and type
27    ///
28    /// This is present only given an explicit identifier *and* an explicit type.
29    pub colon_token: Option<Colon>,
30    /// Field type
31    ///
32    /// In case the type is omitted, this has value [`Type::Infer`].
33    pub ty: Type,
34    /// Optional non-default value assignment
35    pub assignment: Option<(Eq, syn::Expr)>,
36}
37
38/// Contents of `impl_anon!`
39///
40/// The impl_anon macro may be used to conveniently declare a struct's type,
41/// implementations and construct an instance.
42/// This struct represents the macro's input.
43#[derive(Debug)]
44pub struct Anon {
45    /// Struct attributes
46    pub attrs: Vec<Attribute>,
47    /// `struct` token
48    pub token: Token![struct],
49    /// (Explicit) struct generics
50    ///
51    /// Note: the macro instantiated type may have extra generics.
52    pub generics: Generics,
53    /// Struct style: unit/tuple/regular
54    pub style: StructStyle,
55    /// Struct fields
56    pub fields: Punctuated<AnonField, Comma>,
57    /// (Explicit) struct implementations
58    pub impls: Vec<ItemImpl>,
59}
60
61impl Anon {
62    /// Convert to a [`AnonScope`]
63    pub fn into_scope(mut self) -> AnonScope {
64        let mut idfmt = IdentFormatter::new();
65
66        let mut fields = Punctuated::<Field, Comma>::new();
67        let mut field_val_toks = quote! {};
68
69        for (index, pair) in self.fields.into_pairs().enumerate() {
70            let (field, opt_comma) = pair.into_tuple();
71
72            let mut ident = field.ident.clone();
73            let ty = &field.ty;
74            let field_span = match field.assignment {
75                None => quote! { #ty }.span(),
76                Some((ref eq, ref expr)) => quote! { #ty #eq #expr }.span(),
77            };
78            let mem = match self.style {
79                StructStyle::Regular(_) => {
80                    let id = ident
81                        .unwrap_or_else(|| idfmt.make(format_args!("_field{}", index), field_span));
82                    ident = Some(id.clone());
83                    Member::Named(id)
84                }
85                StructStyle::Tuple(_, _) => Member::Unnamed(syn::Index {
86                    index: index as u32,
87                    span: field_span,
88                }),
89                _ => unreachable!(),
90            };
91            let ty_name = match ident {
92                None => format!("_Field{}", index),
93                Some(ref id) => {
94                    let ident = id.to_string();
95                    let mut buf = "_Field".to_string();
96                    buf.reserve(ident.len());
97                    let mut next_upper = true;
98                    for c in ident.chars() {
99                        if c == '_' {
100                            next_upper = true;
101                            continue;
102                        }
103
104                        if next_upper {
105                            buf.extend(c.to_uppercase());
106                            next_upper = false;
107                        } else {
108                            buf.push(c);
109                        }
110                    }
111                    buf
112                }
113            };
114
115            let ty: Type = match field.ty {
116                Type::ImplTrait(syn::TypeImplTrait {
117                    attrs,
118                    impl_token,
119                    bounds,
120                }) => {
121                    error_on_attrs(&attrs);
122
123                    let span = quote! { #impl_token #bounds }.span();
124                    let ty = Ident::new(&ty_name, span);
125
126                    self.generics.params.push(parse_quote! { #ty: #bounds });
127
128                    Type::Path(TypePath {
129                        attrs: vec![],
130                        qself: None,
131                        path: ty.into(),
132                    })
133                }
134                Type::Infer(infer_token) => {
135                    let ty = Ident::new(&ty_name, infer_token.span());
136                    self.generics.params.push(parse_quote! { #ty });
137
138                    Type::Path(TypePath {
139                        attrs: vec![],
140                        qself: None,
141                        path: ty.into(),
142                    })
143                }
144                mut ty => {
145                    struct ReplaceInfers<'a> {
146                        index: usize,
147                        params: Vec<GenericParam>,
148                        idfmt: &'a mut IdentFormatter,
149                        ty_name: &'a str,
150                    }
151                    let mut replacer = ReplaceInfers {
152                        index: 0,
153                        params: vec![],
154                        idfmt: &mut idfmt,
155                        ty_name: &ty_name,
156                    };
157
158                    impl<'a> syn::visit_mut::VisitMut for ReplaceInfers<'a> {
159                        fn visit_type_mut(&mut self, node: &mut Type) {
160                            let (span, bounds) = match node {
161                                Type::ImplTrait(syn::TypeImplTrait {
162                                    attrs,
163                                    impl_token,
164                                    bounds,
165                                }) => {
166                                    error_on_attrs(attrs);
167                                    (impl_token.span, std::mem::take(bounds))
168                                }
169                                Type::Infer(infer) => (infer.span(), Punctuated::new()),
170                                _ => return,
171                            };
172
173                            let ident = self
174                                .idfmt
175                                .make(format_args!("{}{}", self.ty_name, self.index), span);
176                            self.index += 1;
177
178                            self.params.push(GenericParam::Type(syn::TypeParam {
179                                attrs: vec![],
180                                ident: ident.clone(),
181                                colon_token: Some(Default::default()),
182                                bounds,
183                                default: None,
184                            }));
185
186                            *node = Type::Path(TypePath {
187                                attrs: vec![],
188                                qself: None,
189                                path: ident.into(),
190                            });
191                        }
192                    }
193                    syn::visit_mut::visit_type_mut(&mut replacer, &mut ty);
194
195                    self.generics.params.extend(replacer.params);
196                    ty
197                }
198            };
199
200            if let Some((_, ref value)) = field.assignment {
201                field_val_toks.append_all(quote! { #mem: #value, });
202            } else {
203                field_val_toks.append_all(quote! { #mem: Default::default(), });
204            }
205
206            fields.push_value(Field {
207                attrs: field.attrs,
208                vis: field.vis,
209                ident,
210                colon_token: field.colon_token.or_else(|| Some(Default::default())),
211                ty,
212                assign: None,
213            });
214            if let Some(comma) = opt_comma {
215                fields.push_punct(comma);
216            }
217        }
218
219        let (fields, semi) = match self.style {
220            StructStyle::Unit(semi) => (Fields::Unit, Some(semi)),
221            StructStyle::Regular(brace_token) => (
222                Fields::Named(FieldsNamed {
223                    brace_token,
224                    fields,
225                }),
226                None,
227            ),
228            StructStyle::Tuple(paren_token, semi) => (
229                Fields::Unnamed(FieldsUnnamed {
230                    paren_token,
231                    fields,
232                }),
233                Some(semi),
234            ),
235        };
236
237        let scope = Scope {
238            attrs: self.attrs,
239            vis: syn::Visibility::Inherited,
240            ident: parse_quote! { _Anon },
241            generics: self.generics,
242            item: ScopeItem::Struct {
243                token: self.token,
244                fields,
245            },
246            semi,
247            impls: self.impls,
248            generated: vec![],
249        };
250
251        AnonScope(scope, field_val_toks)
252    }
253}
254
255/// A [`Scope`] plus field values
256///
257/// This supports dereference to a [`Scope`], allowing macro expansion via
258/// [`Scope::apply_attrs`] and other manipulation.
259///
260/// Tokens may be generated by [`Self::expand`].
261#[derive(Debug)]
262pub struct AnonScope(Scope, TokenStream);
263
264impl std::ops::Deref for AnonScope {
265    type Target = Scope;
266    fn deref(&self) -> &Scope {
267        &self.0
268    }
269}
270impl std::ops::DerefMut for AnonScope {
271    fn deref_mut(&mut self) -> &mut Scope {
272        &mut self.0
273    }
274}
275
276impl AnonScope {
277    /// Generate the [`TokenStream`]
278    ///
279    /// This is a convenience function. It is valid to, instead, (1) call
280    /// [`Scope::expand_impl_self`] on self, then (2) use the [`ToTokens`]
281    /// impl on `Scope`.
282    pub fn expand(mut self) -> TokenStream {
283        self.expand_impl_self();
284        self.into_token_stream()
285    }
286}
287
288impl ToTokens for AnonScope {
289    fn to_tokens(&self, tokens: &mut TokenStream) {
290        let scope = &self.0;
291        let field_val_toks = &self.1;
292
293        tokens.append_all(quote! {
294            {
295                #scope
296
297                _Anon {
298                    #field_val_toks
299                }
300            }
301        });
302    }
303}
304
305mod parsing {
306    use super::*;
307    use proc_macro_error3::abort;
308    use syn::parse::{Error, Parse, ParseStream, Result};
309    use syn::{braced, parenthesized};
310
311    fn parse_impl(in_ident: Option<&Ident>, input: ParseStream) -> Result<ItemImpl> {
312        let mut attrs = input.call(Attribute::parse_outer)?;
313        let defaultness: Option<Token![default]> = input.parse()?;
314        let unsafety: Option<Token![unsafe]> = input.parse()?;
315        let impl_token: Token![impl] = input.parse()?;
316
317        let has_generics = input.peek(Token![<])
318            && (input.peek2(Token![>])
319                || input.peek2(Token![#])
320                || (input.peek2(Ident) || input.peek2(syn::Lifetime))
321                    && (input.peek3(Token![:])
322                        || input.peek3(Token![,])
323                        || input.peek3(Token![>])
324                        || input.peek3(Token![=]))
325                || input.peek2(Token![const]));
326        let mut generics: Generics = if has_generics {
327            input.parse()?
328        } else {
329            Generics::default()
330        };
331
332        let mut first_ty: Type = input.parse()?;
333        let self_ty: Type;
334        let trait_;
335
336        let is_impl_for = input.peek(Token![for]);
337        if is_impl_for {
338            let for_token: Token![for] = input.parse()?;
339            let mut first_ty_ref = &first_ty;
340            while let Type::Group(ty) = first_ty_ref {
341                first_ty_ref = &ty.elem;
342            }
343            if let Type::Path(_) = first_ty_ref {
344                while let Type::Group(ty) = first_ty {
345                    first_ty = *ty.elem;
346                }
347                if let Type::Path(TypePath {
348                    attrs,
349                    qself: None,
350                    path,
351                }) = first_ty
352                {
353                    error_on_attrs(&attrs);
354                    trait_ = Some((path, for_token));
355                } else {
356                    unreachable!();
357                }
358            } else {
359                return Err(Error::new(for_token.span(), "for without target trait"));
360            }
361            self_ty = input.parse()?;
362        } else {
363            trait_ = None;
364            self_ty = first_ty;
365        }
366
367        generics.where_clause = input.parse()?;
368
369        if self_ty != parse_quote! { Self } {
370            if let Some(ident) = in_ident {
371                if !matches!(self_ty, Type::Path(TypePath {
372                    attrs: _,
373                    qself: None,
374                    path: syn::Path {
375                        leading_colon: None,
376                        ref segments,
377                    }
378                }) if segments.len() == 1 && segments.first().unwrap().ident == *ident)
379                {
380                    abort!(
381                        self_ty.span(),
382                        format!(
383                            "expected `Self` or `{0}` or `{0}<...>` or `Trait for Self`, etc",
384                            ident
385                        )
386                    );
387                }
388            } else {
389                abort!(self_ty.span(), "expected `Self` or `Trait for Self`");
390            }
391        }
392
393        let content;
394        let brace_token = braced!(content in input);
395        attrs.extend(Attribute::parse_inner(&content)?);
396
397        let mut items = Vec::new();
398        while !content.is_empty() {
399            items.push(content.parse()?);
400        }
401
402        let mut modifiers = syn::ImplModifiers::default();
403        modifiers.defaultness = defaultness;
404
405        Ok(ItemImpl {
406            attrs,
407            modifiers,
408            unsafety,
409            impl_token,
410            generics,
411            trait_,
412            self_ty: Box::new(self_ty),
413            brace_token,
414            items,
415        })
416    }
417
418    impl AnonField {
419        fn check_is_fixed(ty: &Type, input_span: Span) -> Result<()> {
420            let is_fixed = match ty {
421                Type::ImplTrait(_) | Type::Infer(_) => false,
422                ty => {
423                    struct IsFixed(bool);
424                    let mut checker = IsFixed(true);
425
426                    impl<'ast> syn::visit::Visit<'ast> for IsFixed {
427                        fn visit_type(&mut self, node: &'ast Type) {
428                            if matches!(node, Type::ImplTrait(_) | Type::Infer(_)) {
429                                self.0 = false;
430                            }
431                        }
432                    }
433                    syn::visit::visit_type(&mut checker, ty);
434
435                    checker.0
436                }
437            };
438
439            if is_fixed {
440                Ok(())
441            } else {
442                Err(Error::new(
443                    input_span,
444                    "require either a fixed type or a value assignment",
445                ))
446            }
447        }
448
449        fn parse_named(input: ParseStream) -> Result<Self> {
450            let attrs = input.call(Attribute::parse_outer)?;
451            let vis = input.parse()?;
452
453            let ident = if input.peek(Token![_]) {
454                let _: Token![_] = input.parse()?;
455                None
456            } else {
457                Some(input.parse::<Ident>()?)
458            };
459
460            let mut colon_token = None;
461
462            // Note: Colon matches `::` but that results in confusing error messages
463            let ty = if input.peek(Colon) && !input.peek2(Colon) {
464                colon_token = Some(input.parse()?);
465                input.parse()?
466            } else {
467                parse_quote! { _ }
468            };
469
470            let mut assignment = None;
471            if let Ok(eq) = input.parse::<Eq>() {
472                assignment = Some((eq, input.parse()?));
473            } else {
474                Self::check_is_fixed(&ty, input.span())?;
475            }
476
477            Ok(AnonField {
478                attrs,
479                vis,
480                ident,
481                colon_token,
482                ty,
483                assignment,
484            })
485        }
486
487        fn parse_unnamed(input: ParseStream) -> Result<Self> {
488            let attrs = input.call(Attribute::parse_outer)?;
489            let vis = input.parse()?;
490
491            let ty = input.parse()?;
492
493            let mut assignment = None;
494            if let Ok(eq) = input.parse::<Eq>() {
495                assignment = Some((eq, input.parse()?));
496            } else {
497                Self::check_is_fixed(&ty, input.span())?;
498            }
499
500            Ok(AnonField {
501                attrs,
502                vis,
503                ident: None,
504                colon_token: None,
505                ty,
506                assignment,
507            })
508        }
509    }
510
511    impl Parse for Anon {
512        fn parse(input: ParseStream) -> Result<Self> {
513            let attrs = input.call(Attribute::parse_outer)?;
514            let token = input.parse::<Token![struct]>()?;
515
516            let mut generics = input.parse::<Generics>()?;
517
518            let mut lookahead = input.lookahead1();
519            if lookahead.peek(Token![where]) {
520                generics.where_clause = Some(input.parse()?);
521                lookahead = input.lookahead1();
522            }
523
524            let style;
525            let fields;
526            if generics.where_clause.is_none() && lookahead.peek(Paren) {
527                let content;
528                let paren_token = parenthesized!(content in input);
529                fields = content.parse_terminated(AnonField::parse_unnamed, Token![,])?;
530
531                lookahead = input.lookahead1();
532                if lookahead.peek(Token![where]) {
533                    generics.where_clause = Some(input.parse()?);
534                    lookahead = input.lookahead1();
535                }
536
537                if lookahead.peek(Semi) {
538                    style = StructStyle::Tuple(paren_token, input.parse()?);
539                } else {
540                    return Err(lookahead.error());
541                }
542            } else if lookahead.peek(Brace) {
543                let content;
544                let brace_token = braced!(content in input);
545                style = StructStyle::Regular(brace_token);
546                fields = content.parse_terminated(AnonField::parse_named, Token![,])?;
547            } else if lookahead.peek(Semi) {
548                style = StructStyle::Unit(input.parse()?);
549                fields = Punctuated::new();
550            } else {
551                return Err(lookahead.error());
552            }
553
554            let mut impls = Vec::new();
555            while !input.is_empty() {
556                impls.push(parse_impl(None, input)?);
557            }
558
559            Ok(Anon {
560                attrs,
561                token,
562                generics,
563                style,
564                fields,
565                impls,
566            })
567        }
568    }
569}