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