Skip to main content

impl_tools_lib/
scope.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_scope!` macro
7
8use crate::{SimplePath, fields::Fields, utils::extend_generics};
9use proc_macro_error3::emit_error;
10use proc_macro2::{Span, TokenStream};
11use quote::{ToTokens, TokenStreamExt};
12use syn::punctuated::Punctuated;
13use syn::spanned::Spanned;
14use syn::token::{Brace, Comma, Semi};
15use syn::{
16    Attribute, FieldsNamed, Generics, Ident, ItemImpl, Path, Result, Token, Type, Variant,
17    Visibility, parse_quote,
18};
19
20pub use super::default::{AttrImplDefault, find_impl_default};
21
22/// Attribute for `#[impl_scope]`
23pub struct ScopeModAttrs;
24
25/// Attribute rule for [`Scope`]
26///
27/// Rules are matched via a path, e.g. `&["foo"]` matches `foo` and
28/// `&["", "foo", "bar"]` matches `::foo::bar`.
29///
30/// Such rules are used to expand attributes within an `impl_scope!`.
31pub trait ScopeAttr {
32    /// Attribute path
33    ///
34    /// Rules are matched via a path, e.g. `&["foo"]` matches `foo` and
35    /// `&["", "foo", "bar"]` matches `::foo::bar`.
36    ///
37    /// Note that we cannot use standard path resolution, so we match only a
38    /// single path, as defined.
39    fn path(&self) -> SimplePath;
40
41    /// Whether repeated application is valid
42    ///
43    /// If this is false (the default), then an error will be omitted on
44    /// repeated usage of the attribute. This mostly serves to emit better error
45    /// messages in cases where the first application modifies the input.
46    fn support_repetition(&self) -> bool {
47        false
48    }
49
50    /// Function type of [`ScopeAttr`] rule
51    ///
52    /// Input arguments:
53    ///
54    /// -   `attr`: the invoking attribute. It is suggested to parse arguments
55    ///     using [`Attribute::parse_args`] or [`Attribute::parse_args_with`].
56    /// -   `scope`: mutable reference to the implementation scope. Usually
57    ///     an attribute rule function will read data from the scope and append its
58    ///     output to [`Scope::generated`].
59    fn apply(&self, attr: Attribute, scope: &mut Scope) -> Result<()>;
60}
61
62/// Content of items supported by [`Scope`] that are not common to all variants
63#[derive(Debug)]
64pub enum ScopeItem {
65    /// A [`syn::ItemEnum`], minus common parts
66    Enum {
67        /// `enum`
68        token: Token![enum],
69        /// `{ ... }`
70        brace: Brace,
71        /// Variants of enum
72        variants: Punctuated<Variant, Comma>,
73    },
74    /// A [`syn::ItemStruct`], minus common parts
75    ///
76    /// Uses custom [`Fields`], supporting field initializers.
77    Struct {
78        /// `struct`
79        token: Token![struct],
80        /// Fields of struct
81        fields: Fields,
82    },
83    /// A [`syn::ItemType`], minus common parts
84    Type {
85        /// `type`
86        token: Token![type],
87        /// `=`
88        eq_token: Token![=],
89        /// Target type
90        ty: Box<Type>,
91    },
92    /// A [`syn::ItemUnion`], minus common parts
93    Union {
94        /// `union`
95        token: Token![union],
96        /// Fields of union
97        fields: FieldsNamed,
98    },
99}
100
101impl ScopeItem {
102    /// Take span of `enum`/`struct`/`type`/`union` token
103    pub fn token_span(&self) -> Span {
104        match self {
105            ScopeItem::Enum { token, .. } => token.span,
106            ScopeItem::Struct { token, .. } => token.span,
107            ScopeItem::Type { token, .. } => token.span,
108            ScopeItem::Union { token, .. } => token.span,
109        }
110    }
111}
112
113/// A module supporting `impl Self` syntax
114///
115/// This type is used for parsing. Expansion should use [`Self::contents`]
116/// directly, ignoring all other fields.
117#[derive(Debug)]
118pub struct ScopeMod {
119    /// Module declaration
120    pub token: Token![mod],
121    /// Module name
122    pub ident: Ident,
123    /// Braces
124    pub brace: Brace,
125    /// Contents
126    pub contents: Scope,
127}
128
129/// Contents of `impl_scope!`
130///
131/// `impl_scope!` input consists of one item (an `enum`, `struct`, `type` alias
132/// or `union`) followed by any number of implementations, and is parsed into
133/// this struct.
134///
135/// On its own, `impl_scope!` provides `impl Self` syntax, with the following
136/// expansion done within [`Self::expand`] (after application [`ScopeAttr`]
137/// rules):
138///
139/// -   `impl Self { ... }` expands to `impl #impl_generics #ty_ident #ty_generics #where_clause { ... }`
140/// -   `impl Self where #clause2 { ... }` expands similarly, but using the combined where clause
141///
142/// The secondary utility of `impl_scope!` is to allow attribute expansion
143/// within itself via [`ScopeAttr`] rules. These rules may read the type item
144/// (which may include field initializers in the case of a struct), read
145/// accompanying implementations, and even modify them.
146#[derive(Debug)]
147pub struct Scope {
148    /// Outer attributes on the item
149    pub attrs: Vec<Attribute>,
150    /// Optional `pub`, etc.
151    pub vis: Visibility,
152    /// Item identifier
153    pub ident: Ident,
154    /// Item generics
155    pub generics: Generics,
156    /// The item
157    pub item: ScopeItem,
158    /// Trailing semicolon (type alias and unit struct only)
159    pub semi: Option<Semi>,
160    /// Implementation items
161    pub impls: Vec<ItemImpl>,
162    /// Output of [`ScopeAttr`] rules
163    ///
164    /// This does not contain any content from input, only content generated
165    /// from [`ScopeAttr`] rules. It is appended to output as an item (usually
166    /// a [`syn::ImplItem`]), after [`Self::impls`] items.
167    pub generated: Vec<TokenStream>,
168}
169
170impl Scope {
171    /// Apply attribute rules
172    ///
173    /// The supplied `rules` are applied in the order of definition, and their
174    /// attributes removed from the item.
175    pub fn apply_attrs(&mut self, find_rule: impl Fn(&Path) -> Option<&'static dyn ScopeAttr>) {
176        let mut applied: Vec<(Span, *const dyn ScopeAttr)> = Vec::new();
177
178        let mut i = 0;
179        while i < self.attrs.len() {
180            if let Some(rule) = find_rule(&self.attrs[i].path()) {
181                let attr = self.attrs.remove(i);
182
183                if !rule.support_repetition() {
184                    // We compare the fat pointer (including vtable address;
185                    // the data may be zero-sized and thus not unique).
186                    // We consider two rules the same when data pointers and
187                    // vtables both compare equal.
188                    let span = attr.span();
189                    let ptr = rule as *const dyn ScopeAttr;
190                    if let Some(first) = applied.iter().find(|(_, p)| std::ptr::eq(*p, ptr)) {
191                        emit_error!(span, "repeated use of attribute not allowed");
192                        emit_error!(first.0, "first usage here");
193                        continue;
194                    }
195                    applied.push((span, ptr));
196                }
197
198                if let Err(err) = rule.apply(attr, self) {
199                    emit_error!(err.span(), "{}", err);
200                }
201                continue;
202            }
203
204            i += 1;
205        }
206    }
207
208    /// Expand `impl Self`
209    ///
210    /// This is done automatically by [`Self::expand`]. It may be called earlier
211    /// by a [`ScopeAttr`] if required. Calling multiple times is harmless.
212    pub fn expand_impl_self(&mut self) {
213        for impl_ in self.impls.iter_mut() {
214            if impl_.self_ty == parse_quote! { Self } {
215                let mut ident = self.ident.clone();
216                ident.set_span(impl_.self_ty.span());
217                let (_, ty_generics, _) = self.generics.split_for_impl();
218                impl_.self_ty = parse_quote! { #ident #ty_generics };
219                extend_generics(&mut impl_.generics, &self.generics);
220            }
221        }
222    }
223
224    /// Generate the [`TokenStream`]
225    ///
226    /// This is a convenience function. It is valid to, instead, (1) call
227    /// [`Self::expand_impl_self`], then (2) use the [`ToTokens`] impl on
228    /// `Scope`.
229    pub fn expand(mut self) -> TokenStream {
230        self.expand_impl_self();
231        self.to_token_stream()
232    }
233}
234
235mod parsing {
236    use super::*;
237    use crate::error_on_attrs;
238    use crate::fields::parsing::data_struct;
239    use syn::parse::{Parse, ParseStream};
240    use syn::spanned::Spanned;
241    use syn::{Error, Field, Lifetime, Path, TypePath, WhereClause, braced};
242
243    impl Parse for ScopeModAttrs {
244        fn parse(_input: ParseStream) -> Result<Self> {
245            Ok(Self)
246        }
247    }
248
249    impl Parse for ScopeMod {
250        fn parse(input: ParseStream) -> Result<Self> {
251            let inner;
252
253            let token = input.parse()?;
254            let ident = input.parse::<Ident>()?;
255            let brace = syn::braced!(inner in input);
256            let contents: Scope = inner.parse()?;
257
258            if ident != contents.ident {
259                return Err(syn::Error::new(
260                    contents.ident.span(),
261                    "type name must match mod name",
262                ));
263            }
264
265            Ok(ScopeMod {
266                token,
267                ident,
268                brace,
269                contents,
270            })
271        }
272    }
273
274    impl Parse for Scope {
275        fn parse(input: ParseStream) -> Result<Self> {
276            let attrs = input.call(Attribute::parse_outer)?;
277            let vis = input.parse::<Visibility>()?;
278
279            enum Token {
280                Enum(Token![enum]),
281                Struct(Token![struct]),
282                Type(Token![type]),
283                Union(Token![union]),
284            }
285            let lookahead = input.lookahead1();
286            let token;
287            if lookahead.peek(Token![enum]) {
288                token = Token::Enum(input.parse()?);
289            } else if lookahead.peek(Token![struct]) {
290                token = Token::Struct(input.parse()?);
291            } else if lookahead.peek(Token![type]) {
292                token = Token::Type(input.parse()?);
293            } else if lookahead.peek(Token![union]) {
294                token = Token::Union(input.parse()?);
295            } else {
296                return Err(lookahead.error());
297            }
298
299            let ident = input.parse::<Ident>()?;
300            let mut generics = input.parse::<Generics>()?;
301
302            let item;
303            let mut semi = None;
304            match token {
305                Token::Enum(token) => {
306                    let (wc, brace, variants) = data_enum(&input)?;
307                    generics.where_clause = wc;
308                    item = ScopeItem::Enum {
309                        token,
310                        brace,
311                        variants,
312                    };
313                }
314                Token::Struct(token) => {
315                    let (wc, fields, semi_token) = data_struct(&input)?;
316                    generics.where_clause = wc;
317                    semi = semi_token;
318                    item = ScopeItem::Struct { token, fields };
319                }
320                Token::Type(token) => {
321                    let eq_token = input.parse()?;
322                    let ty = input.parse()?;
323                    let semi_token = input.parse()?;
324                    semi = Some(semi_token);
325                    item = ScopeItem::Type {
326                        token,
327                        eq_token,
328                        ty,
329                    };
330                }
331                Token::Union(token) => {
332                    let (wc, fields) = data_union(&input)?;
333                    generics.where_clause = wc;
334                    item = ScopeItem::Union { token, fields };
335                }
336            }
337
338            let mut impls = Vec::new();
339            while !input.is_empty() {
340                impls.push(parse_impl(&ident, &input)?);
341            }
342
343            Ok(Scope {
344                attrs,
345                vis,
346                ident,
347                generics,
348                item,
349                semi,
350                impls,
351                generated: vec![],
352            })
353        }
354    }
355
356    fn parse_impl(in_ident: &Ident, input: ParseStream) -> Result<ItemImpl> {
357        let mut attrs = input.call(Attribute::parse_outer)?;
358        let defaultness: Option<Token![default]> = input.parse()?;
359        let unsafety: Option<Token![unsafe]> = input.parse()?;
360        let impl_token: Token![impl] = input.parse()?;
361
362        let has_generics = input.peek(Token![<])
363            && (input.peek2(Token![>])
364                || input.peek2(Token![#])
365                || (input.peek2(Ident) || input.peek2(Lifetime))
366                    && (input.peek3(Token![:])
367                        || input.peek3(Token![,])
368                        || input.peek3(Token![>])
369                        || input.peek3(Token![=]))
370                || input.peek2(Token![const]));
371        let mut generics: Generics = if has_generics {
372            input.parse()?
373        } else {
374            Generics::default()
375        };
376
377        let mut first_ty: Type = input.parse()?;
378        let self_ty: Type;
379        let trait_;
380
381        let is_impl_for = input.peek(Token![for]);
382        if is_impl_for {
383            let for_token: Token![for] = input.parse()?;
384            let mut first_ty_ref = &first_ty;
385            while let Type::Group(ty) = first_ty_ref {
386                first_ty_ref = &ty.elem;
387            }
388            if let Type::Path(_) = first_ty_ref {
389                while let Type::Group(ty) = first_ty {
390                    first_ty = *ty.elem;
391                }
392                if let Type::Path(TypePath {
393                    attrs,
394                    qself: None,
395                    path,
396                }) = first_ty
397                {
398                    error_on_attrs(&attrs);
399                    trait_ = Some((path, for_token));
400                } else {
401                    unreachable!();
402                }
403            } else {
404                return Err(Error::new(for_token.span, "for without target trait"));
405            }
406            self_ty = input.parse()?;
407        } else {
408            trait_ = None;
409            self_ty = first_ty;
410        }
411
412        generics.where_clause = input.parse()?;
413
414        if self_ty != parse_quote! { Self }
415            && !matches!(self_ty, Type::Path(TypePath {
416                attrs: _,
417                qself: None,
418                path: Path {
419                    leading_colon: None,
420                    ref segments,
421                },
422            }) if segments.len() == 1 && segments.first().unwrap().ident == *in_ident)
423        {
424            return Err(Error::new(
425                self_ty.span(),
426                format!(
427                    "expected `Self` or `{0}` or `{0}<...>` or `Trait for Self`, etc",
428                    in_ident
429                ),
430            ));
431        }
432
433        let content;
434        let brace_token = braced!(content in input);
435        attrs.extend(Attribute::parse_inner(&content)?);
436
437        let mut items = Vec::new();
438        while !content.is_empty() {
439            items.push(content.parse()?);
440        }
441
442        let mut modifiers = syn::ImplModifiers::default();
443        modifiers.defaultness = defaultness;
444
445        Ok(ItemImpl {
446            attrs,
447            modifiers,
448            unsafety,
449            impl_token,
450            generics,
451            trait_,
452            self_ty: Box::new(self_ty),
453            brace_token,
454            items,
455        })
456    }
457
458    pub fn data_enum(
459        input: ParseStream,
460    ) -> Result<(Option<WhereClause>, Brace, Punctuated<Variant, Token![,]>)> {
461        let where_clause = input.parse()?;
462
463        let content;
464        let brace = braced!(content in input);
465        let variants = content.parse_terminated(Variant::parse, Token![,])?;
466
467        Ok((where_clause, brace, variants))
468    }
469
470    pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
471        let where_clause = input.parse()?;
472        let fields = parse_braced(input)?;
473        Ok((where_clause, fields))
474    }
475
476    pub(crate) fn parse_braced(input: ParseStream) -> Result<FieldsNamed> {
477        let content;
478        let brace_token = braced!(content in input);
479        let named = content.parse_terminated(Field::parse_named, Token![,])?;
480        Ok(FieldsNamed { brace_token, named })
481    }
482}
483
484mod printing {
485    use super::*;
486
487    impl ToTokens for Scope {
488        fn to_tokens(&self, tokens: &mut TokenStream) {
489            tokens.append_all(self.attrs.iter());
490            self.vis.to_tokens(tokens);
491            match &self.item {
492                ScopeItem::Enum { token, .. } => token.to_tokens(tokens),
493                ScopeItem::Struct { token, .. } => token.to_tokens(tokens),
494                ScopeItem::Type { token, .. } => token.to_tokens(tokens),
495                ScopeItem::Union { token, .. } => token.to_tokens(tokens),
496            }
497            self.ident.to_tokens(tokens);
498            self.generics.to_tokens(tokens);
499            match &self.item {
500                ScopeItem::Enum {
501                    brace, variants, ..
502                } => {
503                    self.generics.where_clause.to_tokens(tokens);
504                    brace.surround(tokens, |tokens| {
505                        variants.to_tokens(tokens);
506                    });
507                }
508                ScopeItem::Struct { fields, .. } => match fields {
509                    Fields::Named(fields) => {
510                        self.generics.where_clause.to_tokens(tokens);
511                        fields.to_tokens(tokens);
512                    }
513                    Fields::Unnamed(fields) => {
514                        fields.to_tokens(tokens);
515                        self.generics.where_clause.to_tokens(tokens);
516                    }
517                    Fields::Unit => {
518                        self.generics.where_clause.to_tokens(tokens);
519                    }
520                },
521                ScopeItem::Type { eq_token, ty, .. } => {
522                    self.generics.where_clause.to_tokens(tokens);
523                    eq_token.to_tokens(tokens);
524                    ty.to_tokens(tokens);
525                }
526                ScopeItem::Union { fields, .. } => {
527                    self.generics.where_clause.to_tokens(tokens);
528                    fields.to_tokens(tokens);
529                }
530            }
531            if let Some(semi) = self.semi.as_ref() {
532                semi.to_tokens(tokens);
533            }
534
535            tokens.append_all(self.impls.iter());
536            tokens.append_all(self.generated.iter());
537        }
538    }
539}