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;
11use proc_macro2::{Span, TokenStream};
12use quote::{quote, ToTokens, TokenStreamExt};
13use syn::token::{Brace, Colon, Comma, Eq, Paren, Semi};
14use syn::{parse_quote, punctuated::Punctuated, spanned::Spanned};
15use syn::{Attribute, GenericParam, Generics, Ident, ItemImpl, Member, Token, Type, TypePath};
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 { impl_token, bounds }) => {
117                    let span = quote! { #impl_token #bounds }.span();
118                    let ty = Ident::new(&ty_name, span);
119
120                    self.generics.params.push(parse_quote! { #ty: #bounds });
121
122                    Type::Path(TypePath {
123                        qself: None,
124                        path: ty.into(),
125                    })
126                }
127                Type::Infer(infer_token) => {
128                    let ty = Ident::new(&ty_name, infer_token.span());
129                    self.generics.params.push(parse_quote! { #ty });
130
131                    Type::Path(TypePath {
132                        qself: None,
133                        path: ty.into(),
134                    })
135                }
136                mut ty => {
137                    struct ReplaceInfers<'a> {
138                        index: usize,
139                        params: Vec<GenericParam>,
140                        idfmt: &'a mut IdentFormatter,
141                        ty_name: &'a str,
142                    }
143                    let mut replacer = ReplaceInfers {
144                        index: 0,
145                        params: vec![],
146                        idfmt: &mut idfmt,
147                        ty_name: &ty_name,
148                    };
149
150                    impl<'a> syn::visit_mut::VisitMut for ReplaceInfers<'a> {
151                        fn visit_type_mut(&mut self, node: &mut Type) {
152                            let (span, bounds) = match node {
153                                Type::ImplTrait(syn::TypeImplTrait { impl_token, bounds }) => {
154                                    (impl_token.span, std::mem::take(bounds))
155                                }
156                                Type::Infer(infer) => (infer.span(), Punctuated::new()),
157                                _ => return,
158                            };
159
160                            let ident = self
161                                .idfmt
162                                .make(format_args!("{}{}", self.ty_name, self.index), span);
163                            self.index += 1;
164
165                            self.params.push(GenericParam::Type(syn::TypeParam {
166                                attrs: vec![],
167                                ident: ident.clone(),
168                                colon_token: Some(Default::default()),
169                                bounds,
170                                eq_token: None,
171                                default: None,
172                            }));
173
174                            *node = Type::Path(TypePath {
175                                qself: None,
176                                path: ident.into(),
177                            });
178                        }
179                    }
180                    syn::visit_mut::visit_type_mut(&mut replacer, &mut ty);
181
182                    self.generics.params.extend(replacer.params);
183                    ty
184                }
185            };
186
187            if let Some((_, ref value)) = field.assignment {
188                field_val_toks.append_all(quote! { #mem: #value, });
189            } else {
190                field_val_toks.append_all(quote! { #mem: Default::default(), });
191            }
192
193            fields.push_value(Field {
194                attrs: field.attrs,
195                vis: field.vis,
196                ident,
197                colon_token: field.colon_token.or_else(|| Some(Default::default())),
198                ty,
199                assign: None,
200            });
201            if let Some(comma) = opt_comma {
202                fields.push_punct(comma);
203            }
204        }
205
206        let (fields, semi) = match self.style {
207            StructStyle::Unit(semi) => (Fields::Unit, Some(semi)),
208            StructStyle::Regular(brace_token) => (
209                Fields::Named(FieldsNamed {
210                    brace_token,
211                    fields,
212                }),
213                None,
214            ),
215            StructStyle::Tuple(paren_token, semi) => (
216                Fields::Unnamed(FieldsUnnamed {
217                    paren_token,
218                    fields,
219                }),
220                Some(semi),
221            ),
222        };
223
224        let scope = Scope {
225            attrs: self.attrs,
226            vis: syn::Visibility::Inherited,
227            ident: parse_quote! { _Anon },
228            generics: self.generics,
229            item: ScopeItem::Struct {
230                token: self.token,
231                fields,
232            },
233            semi,
234            impls: self.impls,
235            generated: vec![],
236        };
237
238        AnonScope(scope, field_val_toks)
239    }
240}
241
242/// A [`Scope`] plus field values
243///
244/// This supports dereference to a [`Scope`], allowing macro expansion via
245/// [`Scope::apply_attrs`] and other manipulation.
246///
247/// Tokens may be generated by [`Self::expand`].
248#[derive(Debug)]
249pub struct AnonScope(Scope, TokenStream);
250
251impl std::ops::Deref for AnonScope {
252    type Target = Scope;
253    fn deref(&self) -> &Scope {
254        &self.0
255    }
256}
257impl std::ops::DerefMut for AnonScope {
258    fn deref_mut(&mut self) -> &mut Scope {
259        &mut self.0
260    }
261}
262
263impl AnonScope {
264    /// Generate the [`TokenStream`]
265    ///
266    /// This is a convenience function. It is valid to, instead, (1) call
267    /// [`Scope::expand_impl_self`] on self, then (2) use the [`ToTokens`]
268    /// impl on `Scope`.
269    pub fn expand(mut self) -> TokenStream {
270        self.expand_impl_self();
271        self.into_token_stream()
272    }
273}
274
275impl ToTokens for AnonScope {
276    fn to_tokens(&self, tokens: &mut TokenStream) {
277        let scope = &self.0;
278        let field_val_toks = &self.1;
279
280        tokens.append_all(quote! {
281            {
282                #scope
283
284                _Anon {
285                    #field_val_toks
286                }
287            }
288        });
289    }
290}
291
292mod parsing {
293    use super::*;
294    use proc_macro_error2::abort;
295    use syn::parse::{Error, Parse, ParseStream, Result};
296    use syn::{braced, parenthesized};
297
298    fn parse_impl(in_ident: Option<&Ident>, input: ParseStream) -> Result<ItemImpl> {
299        let mut attrs = input.call(Attribute::parse_outer)?;
300        let defaultness: Option<Token![default]> = input.parse()?;
301        let unsafety: Option<Token![unsafe]> = input.parse()?;
302        let impl_token: Token![impl] = input.parse()?;
303
304        let has_generics = input.peek(Token![<])
305            && (input.peek2(Token![>])
306                || input.peek2(Token![#])
307                || (input.peek2(Ident) || input.peek2(syn::Lifetime))
308                    && (input.peek3(Token![:])
309                        || input.peek3(Token![,])
310                        || input.peek3(Token![>])
311                        || input.peek3(Token![=]))
312                || input.peek2(Token![const]));
313        let mut generics: Generics = if has_generics {
314            input.parse()?
315        } else {
316            Generics::default()
317        };
318
319        let mut first_ty: Type = input.parse()?;
320        let self_ty: Type;
321        let trait_;
322
323        let is_impl_for = input.peek(Token![for]);
324        if is_impl_for {
325            let for_token: Token![for] = input.parse()?;
326            let mut first_ty_ref = &first_ty;
327            while let Type::Group(ty) = first_ty_ref {
328                first_ty_ref = &ty.elem;
329            }
330            if let Type::Path(_) = first_ty_ref {
331                while let Type::Group(ty) = first_ty {
332                    first_ty = *ty.elem;
333                }
334                if let Type::Path(TypePath { qself: None, path }) = first_ty {
335                    trait_ = Some((None, path, for_token));
336                } else {
337                    unreachable!();
338                }
339            } else {
340                return Err(Error::new(for_token.span(), "for without target trait"));
341            }
342            self_ty = input.parse()?;
343        } else {
344            trait_ = None;
345            self_ty = first_ty;
346        }
347
348        generics.where_clause = input.parse()?;
349
350        if self_ty != parse_quote! { Self } {
351            if let Some(ident) = in_ident {
352                if !matches!(self_ty, Type::Path(TypePath {
353                    qself: None,
354                    path: syn::Path {
355                        leading_colon: None,
356                        ref segments,
357                    }
358                }) if segments.len() == 1 && segments.first().unwrap().ident == *ident)
359                {
360                    abort!(
361                        self_ty.span(),
362                        format!(
363                            "expected `Self` or `{0}` or `{0}<...>` or `Trait for Self`, etc",
364                            ident
365                        )
366                    );
367                }
368            } else {
369                abort!(self_ty.span(), "expected `Self` or `Trait for Self`");
370            }
371        }
372
373        let content;
374        let brace_token = braced!(content in input);
375        attrs.extend(Attribute::parse_inner(&content)?);
376
377        let mut items = Vec::new();
378        while !content.is_empty() {
379            items.push(content.parse()?);
380        }
381
382        Ok(ItemImpl {
383            attrs,
384            defaultness,
385            unsafety,
386            impl_token,
387            generics,
388            trait_,
389            self_ty: Box::new(self_ty),
390            brace_token,
391            items,
392        })
393    }
394
395    impl AnonField {
396        fn check_is_fixed(ty: &Type, input_span: Span) -> Result<()> {
397            let is_fixed = match ty {
398                Type::ImplTrait(_) | Type::Infer(_) => false,
399                ty => {
400                    struct IsFixed(bool);
401                    let mut checker = IsFixed(true);
402
403                    impl<'ast> syn::visit::Visit<'ast> for IsFixed {
404                        fn visit_type(&mut self, node: &'ast Type) {
405                            if matches!(node, Type::ImplTrait(_) | Type::Infer(_)) {
406                                self.0 = false;
407                            }
408                        }
409                    }
410                    syn::visit::visit_type(&mut checker, ty);
411
412                    checker.0
413                }
414            };
415
416            if is_fixed {
417                Ok(())
418            } else {
419                Err(Error::new(
420                    input_span,
421                    "require either a fixed type or a value assignment",
422                ))
423            }
424        }
425
426        fn parse_named(input: ParseStream) -> Result<Self> {
427            let attrs = input.call(Attribute::parse_outer)?;
428            let vis = input.parse()?;
429
430            let ident = if input.peek(Token![_]) {
431                let _: Token![_] = input.parse()?;
432                None
433            } else {
434                Some(input.parse::<Ident>()?)
435            };
436
437            let mut colon_token = None;
438
439            // Note: Colon matches `::` but that results in confusing error messages
440            let ty = if input.peek(Colon) && !input.peek2(Colon) {
441                colon_token = Some(input.parse()?);
442                input.parse()?
443            } else {
444                parse_quote! { _ }
445            };
446
447            let mut assignment = None;
448            if let Ok(eq) = input.parse::<Eq>() {
449                assignment = Some((eq, input.parse()?));
450            } else {
451                Self::check_is_fixed(&ty, input.span())?;
452            }
453
454            Ok(AnonField {
455                attrs,
456                vis,
457                ident,
458                colon_token,
459                ty,
460                assignment,
461            })
462        }
463
464        fn parse_unnamed(input: ParseStream) -> Result<Self> {
465            let attrs = input.call(Attribute::parse_outer)?;
466            let vis = input.parse()?;
467
468            let ty = input.parse()?;
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: None,
481                colon_token: None,
482                ty,
483                assignment,
484            })
485        }
486    }
487
488    impl Parse for Anon {
489        fn parse(input: ParseStream) -> Result<Self> {
490            let attrs = input.call(Attribute::parse_outer)?;
491            let token = input.parse::<Token![struct]>()?;
492
493            let mut generics = input.parse::<Generics>()?;
494
495            let mut lookahead = input.lookahead1();
496            if lookahead.peek(Token![where]) {
497                generics.where_clause = Some(input.parse()?);
498                lookahead = input.lookahead1();
499            }
500
501            let style;
502            let fields;
503            if generics.where_clause.is_none() && lookahead.peek(Paren) {
504                let content;
505                let paren_token = parenthesized!(content in input);
506                fields = content.parse_terminated(AnonField::parse_unnamed, Token![,])?;
507
508                lookahead = input.lookahead1();
509                if lookahead.peek(Token![where]) {
510                    generics.where_clause = Some(input.parse()?);
511                    lookahead = input.lookahead1();
512                }
513
514                if lookahead.peek(Semi) {
515                    style = StructStyle::Tuple(paren_token, input.parse()?);
516                } else {
517                    return Err(lookahead.error());
518                }
519            } else if lookahead.peek(Brace) {
520                let content;
521                let brace_token = braced!(content in input);
522                style = StructStyle::Regular(brace_token);
523                fields = content.parse_terminated(AnonField::parse_named, Token![,])?;
524            } else if lookahead.peek(Semi) {
525                style = StructStyle::Unit(input.parse()?);
526                fields = Punctuated::new();
527            } else {
528                return Err(lookahead.error());
529            }
530
531            let mut impls = Vec::new();
532            while !input.is_empty() {
533                impls.push(parse_impl(None, input)?);
534            }
535
536            Ok(Anon {
537                attrs,
538                token,
539                generics,
540                style,
541                fields,
542                impls,
543            })
544        }
545    }
546}