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::{fields::Fields, SimplePath};
9use proc_macro2::{Span, TokenStream};
10use proc_macro_error2::emit_error;
11use quote::{ToTokens, TokenStreamExt};
12use syn::punctuated::Punctuated;
13use syn::spanned::Spanned;
14use syn::token::{Brace, Comma, Semi};
15use syn::{
16    parse_quote, Attribute, FieldsNamed, GenericParam, Generics, Ident, ItemImpl, Path, Result,
17    Token, Type, Variant, Visibility,
18};
19
20pub use super::default::{find_impl_default, AttrImplDefault};
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::fields::parsing::data_struct;
238    use syn::parse::{Parse, ParseStream};
239    use syn::spanned::Spanned;
240    use syn::{braced, Error, Field, Lifetime, Path, TypePath, WhereClause};
241
242    impl Parse for ScopeModAttrs {
243        fn parse(_input: ParseStream) -> Result<Self> {
244            Ok(Self)
245        }
246    }
247
248    impl Parse for ScopeMod {
249        fn parse(input: ParseStream) -> Result<Self> {
250            let inner;
251
252            let token = input.parse()?;
253            let ident = input.parse::<Ident>()?;
254            let brace = syn::braced!(inner in input);
255            let contents: Scope = inner.parse()?;
256
257            if ident != contents.ident {
258                return Err(syn::Error::new(
259                    contents.ident.span(),
260                    "type name must match mod name",
261                ));
262            }
263
264            Ok(ScopeMod {
265                token,
266                ident,
267                brace,
268                contents,
269            })
270        }
271    }
272
273    impl Parse for Scope {
274        fn parse(input: ParseStream) -> Result<Self> {
275            let attrs = input.call(Attribute::parse_outer)?;
276            let vis = input.parse::<Visibility>()?;
277
278            enum Token {
279                Enum(Token![enum]),
280                Struct(Token![struct]),
281                Type(Token![type]),
282                Union(Token![union]),
283            }
284            let lookahead = input.lookahead1();
285            let token;
286            if lookahead.peek(Token![enum]) {
287                token = Token::Enum(input.parse()?);
288            } else if lookahead.peek(Token![struct]) {
289                token = Token::Struct(input.parse()?);
290            } else if lookahead.peek(Token![type]) {
291                token = Token::Type(input.parse()?);
292            } else if lookahead.peek(Token![union]) {
293                token = Token::Union(input.parse()?);
294            } else {
295                return Err(lookahead.error());
296            }
297
298            let ident = input.parse::<Ident>()?;
299            let mut generics = input.parse::<Generics>()?;
300
301            let item;
302            let mut semi = None;
303            match token {
304                Token::Enum(token) => {
305                    let (wc, brace, variants) = data_enum(&input)?;
306                    generics.where_clause = wc;
307                    item = ScopeItem::Enum {
308                        token,
309                        brace,
310                        variants,
311                    };
312                }
313                Token::Struct(token) => {
314                    let (wc, fields, semi_token) = data_struct(&input)?;
315                    generics.where_clause = wc;
316                    semi = semi_token;
317                    item = ScopeItem::Struct { token, fields };
318                }
319                Token::Type(token) => {
320                    let eq_token = input.parse()?;
321                    let ty = input.parse()?;
322                    let semi_token = input.parse()?;
323                    semi = Some(semi_token);
324                    item = ScopeItem::Type {
325                        token,
326                        eq_token,
327                        ty,
328                    };
329                }
330                Token::Union(token) => {
331                    let (wc, fields) = data_union(&input)?;
332                    generics.where_clause = wc;
333                    item = ScopeItem::Union { token, fields };
334                }
335            }
336
337            let mut impls = Vec::new();
338            while !input.is_empty() {
339                impls.push(parse_impl(&ident, &input)?);
340            }
341
342            Ok(Scope {
343                attrs,
344                vis,
345                ident,
346                generics,
347                item,
348                semi,
349                impls,
350                generated: vec![],
351            })
352        }
353    }
354
355    fn parse_impl(in_ident: &Ident, input: ParseStream) -> Result<ItemImpl> {
356        let mut attrs = input.call(Attribute::parse_outer)?;
357        let defaultness: Option<Token![default]> = input.parse()?;
358        let unsafety: Option<Token![unsafe]> = input.parse()?;
359        let impl_token: Token![impl] = input.parse()?;
360
361        let has_generics = input.peek(Token![<])
362            && (input.peek2(Token![>])
363                || input.peek2(Token![#])
364                || (input.peek2(Ident) || input.peek2(Lifetime))
365                    && (input.peek3(Token![:])
366                        || input.peek3(Token![,])
367                        || input.peek3(Token![>])
368                        || input.peek3(Token![=]))
369                || input.peek2(Token![const]));
370        let mut generics: Generics = if has_generics {
371            input.parse()?
372        } else {
373            Generics::default()
374        };
375
376        let mut first_ty: Type = input.parse()?;
377        let self_ty: Type;
378        let trait_;
379
380        let is_impl_for = input.peek(Token![for]);
381        if is_impl_for {
382            let for_token: Token![for] = input.parse()?;
383            let mut first_ty_ref = &first_ty;
384            while let Type::Group(ty) = first_ty_ref {
385                first_ty_ref = &ty.elem;
386            }
387            if let Type::Path(_) = first_ty_ref {
388                while let Type::Group(ty) = first_ty {
389                    first_ty = *ty.elem;
390                }
391                if let Type::Path(TypePath { qself: None, path }) = first_ty {
392                    trait_ = Some((None, path, for_token));
393                } else {
394                    unreachable!();
395                }
396            } else {
397                return Err(Error::new(for_token.span, "for without target trait"));
398            }
399            self_ty = input.parse()?;
400        } else {
401            trait_ = None;
402            self_ty = first_ty;
403        }
404
405        generics.where_clause = input.parse()?;
406
407        if self_ty != parse_quote! { Self }
408            && !matches!(self_ty, Type::Path(TypePath {
409                qself: None,
410                path: Path {
411                    leading_colon: None,
412                    ref segments,
413                }
414            }) if segments.len() == 1 && segments.first().unwrap().ident == *in_ident)
415        {
416            return Err(Error::new(
417                self_ty.span(),
418                format!(
419                    "expected `Self` or `{0}` or `{0}<...>` or `Trait for Self`, etc",
420                    in_ident
421                ),
422            ));
423        }
424
425        let content;
426        let brace_token = braced!(content in input);
427        attrs.extend(Attribute::parse_inner(&content)?);
428
429        let mut items = Vec::new();
430        while !content.is_empty() {
431            items.push(content.parse()?);
432        }
433
434        Ok(ItemImpl {
435            attrs,
436            defaultness,
437            unsafety,
438            impl_token,
439            generics,
440            trait_,
441            self_ty: Box::new(self_ty),
442            brace_token,
443            items,
444        })
445    }
446
447    pub fn data_enum(
448        input: ParseStream,
449    ) -> Result<(Option<WhereClause>, Brace, Punctuated<Variant, Token![,]>)> {
450        let where_clause = input.parse()?;
451
452        let content;
453        let brace = braced!(content in input);
454        let variants = content.parse_terminated(Variant::parse, Token![,])?;
455
456        Ok((where_clause, brace, variants))
457    }
458
459    pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
460        let where_clause = input.parse()?;
461        let fields = parse_braced(input)?;
462        Ok((where_clause, fields))
463    }
464
465    pub(crate) fn parse_braced(input: ParseStream) -> Result<FieldsNamed> {
466        let content;
467        let brace_token = braced!(content in input);
468        let named = content.parse_terminated(Field::parse_named, Token![,])?;
469        Ok(FieldsNamed { brace_token, named })
470    }
471}
472
473mod printing {
474    use super::*;
475
476    impl ToTokens for Scope {
477        fn to_tokens(&self, tokens: &mut TokenStream) {
478            tokens.append_all(self.attrs.iter());
479            self.vis.to_tokens(tokens);
480            match &self.item {
481                ScopeItem::Enum { token, .. } => token.to_tokens(tokens),
482                ScopeItem::Struct { token, .. } => token.to_tokens(tokens),
483                ScopeItem::Type { token, .. } => token.to_tokens(tokens),
484                ScopeItem::Union { token, .. } => token.to_tokens(tokens),
485            }
486            self.ident.to_tokens(tokens);
487            self.generics.to_tokens(tokens);
488            match &self.item {
489                ScopeItem::Enum {
490                    brace, variants, ..
491                } => {
492                    self.generics.where_clause.to_tokens(tokens);
493                    brace.surround(tokens, |tokens| {
494                        variants.to_tokens(tokens);
495                    });
496                }
497                ScopeItem::Struct { fields, .. } => match fields {
498                    Fields::Named(fields) => {
499                        self.generics.where_clause.to_tokens(tokens);
500                        fields.to_tokens(tokens);
501                    }
502                    Fields::Unnamed(fields) => {
503                        fields.to_tokens(tokens);
504                        self.generics.where_clause.to_tokens(tokens);
505                    }
506                    Fields::Unit => {
507                        self.generics.where_clause.to_tokens(tokens);
508                    }
509                },
510                ScopeItem::Type { eq_token, ty, .. } => {
511                    self.generics.where_clause.to_tokens(tokens);
512                    eq_token.to_tokens(tokens);
513                    ty.to_tokens(tokens);
514                }
515                ScopeItem::Union { fields, .. } => {
516                    self.generics.where_clause.to_tokens(tokens);
517                    fields.to_tokens(tokens);
518                }
519            }
520            if let Some(semi) = self.semi.as_ref() {
521                semi.to_tokens(tokens);
522            }
523
524            tokens.append_all(self.impls.iter());
525            tokens.append_all(self.generated.iter());
526        }
527    }
528}
529
530// Support impls on Self by replacing name and summing generics
531fn extend_generics(generics: &mut Generics, in_generics: &Generics) {
532    if generics.lt_token.is_none() {
533        debug_assert!(generics.params.is_empty());
534        debug_assert!(generics.gt_token.is_none());
535        generics.lt_token = in_generics.lt_token;
536        generics.params = in_generics.params.clone();
537        generics.gt_token = in_generics.gt_token;
538    } else if in_generics.lt_token.is_none() {
539        debug_assert!(in_generics.params.is_empty());
540        debug_assert!(in_generics.gt_token.is_none());
541    } else {
542        if !generics.params.empty_or_trailing() {
543            generics.params.push_punct(Default::default());
544        }
545        generics
546            .params
547            .extend(in_generics.params.clone().into_pairs());
548    }
549
550    // Strip defaults which are legal on the struct but not on impls
551    for param in &mut generics.params {
552        match param {
553            GenericParam::Type(p) => {
554                p.eq_token = None;
555                p.default = None;
556            }
557            GenericParam::Lifetime(_) => (),
558            GenericParam::Const(p) => {
559                p.eq_token = None;
560                p.default = None;
561            }
562        }
563    }
564
565    if let Some(ref mut clause1) = generics.where_clause {
566        if let Some(ref clause2) = in_generics.where_clause {
567            if !clause1.predicates.empty_or_trailing() {
568                clause1.predicates.push_punct(Default::default());
569            }
570            clause1
571                .predicates
572                .extend(clause2.predicates.clone().into_pairs());
573        }
574    } else {
575        generics.where_clause = in_generics.where_clause.clone();
576    }
577}