inheritance_proc_macro/
mod.rs

1#![allow(non_snake_case, unused_imports)]
2
3extern crate proc_macro;
4
5#[macro_use]
6extern crate fstrings;
7
8use ::proc_macro::{
9    TokenStream,
10};
11use ::proc_macro2::{
12    Span,
13    TokenStream as TokenStream2,
14};
15use ::quote::{
16    quote,
17    quote_spanned,
18};
19use ::syn::{*,
20    parse::{
21        Parse,
22        ParseStream,
23    },
24    spanned::Spanned,
25};
26use ::std::{*,
27    convert::{TryInto, TryFrom},
28    iter::FromIterator,
29    result::Result,
30};
31
32#[macro_use]
33mod macros;
34
35#[inline]
36fn take<T : Default> (x: &'_ mut T)
37  -> T
38{
39    mem::replace(x, T::default())
40}
41
42#[proc_macro_attribute] pub
43fn inheritable (params: TokenStream, input: TokenStream)
44  -> TokenStream
45{
46    // === Parse / extraction logic ===
47    #[cfg_attr(feature = "verbose-expansions",
48        derive(Debug),
49    )]
50    #[allow(dead_code)] // dumb compiler...
51    struct Trait {
52        ident: Ident,
53        methods: Vec<TraitItemMethod>,
54    }
55
56    impl Parse for Trait {
57        fn parse (input: ParseStream) -> syn::Result<Self>
58        {Ok({
59            let ItemTrait {
60                    ident,
61                    items,
62                    generics,
63                    ..
64                } = input.parse()?
65            ;
66            match (
67                generics.type_params().next(),
68                generics.lifetimes().next(),
69                generics.const_params().next(),
70            )
71            {
72                | (None, None, None) => {},
73
74                | _ => parse_error!(
75                    generics.span(),
76                    "Trait generics are not supported (yet)",
77                ),
78            }
79            let methods: Vec<TraitItemMethod> =
80                items
81                    .into_iter()
82                    //  error on non-function items
83                    .map(|trait_item| match trait_item {
84                        | TraitItem::Method(method) => Ok(method),
85                        | _ => parse_error!(
86                            trait_item.span(),
87                            "`#[inheritable]` currently only supports methods"
88                        ),
89                    })
90                    // error on non-method functions
91                    .map(|x| x.and_then(|method| {
92                        let ref sig = method.sig;
93                        let mut span = sig.ident.span();
94                        match sig.inputs.iter().next() {
95                            // & [mut] self
96                            | Some(&FnArg::Receiver(Receiver {
97                                reference: Some(_),
98                                ..
99                            }))
100                            => {},
101
102                            // self: & [mut] _
103                            | Some(&FnArg::Typed(PatType {
104                                ref pat,
105                                ref ty,
106                                ..
107                            }))
108                                if match (&**pat, &**ty) {
109                                    | (
110                                        &Pat::Ident(PatIdent { ref ident, .. }),
111                                        &Type::Reference(_),
112                                    ) => {
113                                        ident == "self"
114                                    },
115
116                                    | _ => false,
117                                }
118                            => {},
119
120                            // otherwise
121                            | opt_arg => {
122                                if let Some(arg) = opt_arg {
123                                    span = arg.span();
124                                }
125                                parse_error!(span, concat!(
126                                    "associated function requires a ",
127                                    "`&self` or `&mut self` receiver",
128                                ));
129                            },
130                        }
131                        Ok(method)
132                    }))
133                    .collect::<Result<_, _>>()?
134            ;
135            Self {
136                ident,
137                methods,
138            }
139        })}
140    }
141
142
143    set_output!( render => ret );
144
145    debug!(concat!(
146        "-------------------------\n",
147        "#[inheritable({params})]\n",
148        "{input}\n",
149    ), params=params, input=input);
150
151
152    // === This macro does not expect params ===
153    let params = TokenStream2::from(params);
154    if params.clone().into_iter().next().is_some() {
155        error!(params.span(), "Unexpected parameter(s)");
156    }
157
158    // === Parse the input ===
159    let Trait {
160        ident: Trait,
161        mut methods,
162    } = {
163        let input = input.clone();
164        parse_macro_input!(input)
165    };
166
167
168    // === Render the decorated trait itself (as is) ===
169    ret.extend(input);
170
171
172    // === Render the helper `Inherits#Trait` trait ===
173    let InheritsTrait = Ident::new(&f!(
174        "__Inherits{Trait}__"
175    ), Span::call_site());
176
177    ret.extend({
178        // Due to a bug in `quote!`, we need to render
179        // `#[doc(hidden)]`
180        // manually
181        use ::proc_macro::*;
182        iter::once(TokenTree::Punct(Punct::new(
183            '#',
184        Spacing::Alone))).chain(TokenStream::from(::quote::quote! {
185            [doc(hidden)]
186        }))
187    });
188    render! {
189        pub(in crate)
190        trait #InheritsTrait {
191            type __Parent__
192                : #Trait
193            ;
194            fn __parent__ (self: &'_ Self)
195              -> &'_ Self::__Parent__
196            ;
197            fn __parent_mut__ (self: &'_ mut Self)
198              -> &'_ mut Self::__Parent__
199            ;
200        }
201    };
202
203
204    // === Render the default impl of `Trait` for `InheritsTrait` implemetors ===
205    methods
206        .iter_mut()
207        .for_each(|method| {
208            let &mut TraitItemMethod {
209                sig: Signature {
210                    ref ident,
211                    ref generics,
212                    ref mut inputs,
213                    ..
214                },
215                ref mut default,
216                ref mut semi_token,
217                ref mut attrs,
218            } = method;
219            *attrs = vec![];
220            *semi_token = None;
221            let mut args: Vec<Ident> =
222                Vec::with_capacity(
223                    inputs
224                        .len()
225                        .saturating_sub(1)
226                )
227            ;
228            let mut inputs_iter = take(inputs).into_iter();
229            let mut parent_mb_mut = TokenStream2::default();
230            *inputs =
231                inputs_iter
232                    .next()
233                    .map(|first_arg| {
234                        if match first_arg {
235                            | FnArg::Receiver(Receiver {
236                                ref mutability,
237                                ..
238                            }) => {
239                                mutability.is_some()
240                            },
241                        // with box patterns we'd be able to merge both cases...
242                            | FnArg::Typed(PatType { ref ty, .. }) => {
243                                match &**ty {
244                                    | &Type::Reference(TypeReference {
245                                        ref mutability,
246                                        ..
247                                    }) => {
248                                        mutability.is_some()
249                                    },
250
251                                    | _ => unreachable!(),
252                                }
253                            },
254                        } {
255                            parent_mb_mut = quote!( __parent_mut__ );
256                        } else {
257                            parent_mb_mut = quote!( __parent__ );
258                        }
259                        first_arg
260                    })
261                    .into_iter()
262                    .chain(
263                        inputs_iter
264                            .zip(1 ..)
265                            .map(|(mut arg, i)| match arg {
266                                | FnArg::Typed(PatType { ref mut pat, .. }) => {
267                                    let ident = Ident::new(&f!(
268                                        "arg_{i}"
269                                    ), Span::call_site());
270                                    *pat = parse_quote! {
271                                        #ident
272                                    };
273                                    args.push(ident);
274                                    arg
275                                },
276
277                                | _ => unreachable!("Invalid method signature"),
278                            })
279                    )
280                    .collect()
281            ;
282            let generics = generics.split_for_impl().1;
283            let generics = generics.as_turbofish();
284            // method body
285            *default = Some(parse_quote! {
286                {
287                    /* 100% guaranteed unambiguous version */
288                    // <
289                    //     <Self as #InheritsTrait>::__Parent__
290                    //     as #Trait
291                    // >::#ident #generics (
292                    //     #InheritsTrait :: #parent_mb_mut(self),
293                    //     #(#args),*
294                    // )
295                    /* This should nevertheless also be unambiguous */
296                    self.#parent_mb_mut()
297                        .#ident #generics (
298                            #(#args),*
299                        )
300                }
301            });
302        })
303    ;
304    let default_if_specialization =
305        if cfg!(feature = "specialization") {
306            quote!( default )
307        } else {
308            TokenStream2::new()
309        }
310    ;
311    render! {
312        impl<__inheritable_T__ : #InheritsTrait> #Trait
313            for __inheritable_T__
314        {
315            #(
316                #[inline]
317                #default_if_specialization
318                #methods
319            )*
320        }
321    }
322
323
324    debug!("=> becomes =>\n\n{}\n-------------------------\n", ret);
325
326
327    ret
328}
329
330#[proc_macro_derive(Inheritance, attributes(inherits))] pub
331fn derive_Inheritance (input: TokenStream)
332  -> TokenStream
333{
334    debug!(concat!(
335        "-------------------------\n",
336        "#[derive(Inheritance)]\n",
337        "{input}\n",
338        "\n",
339    ), input=input);
340
341    set_output!( render => ret );
342
343    let DeriveInput {
344            ident: Struct,
345            generics,
346            data,
347            ..
348        } = parse_macro_input!(input)
349    ;
350    let fields = match data {
351        | Data::Struct(DataStruct { fields, .. }) => fields,
352        | Data::Enum(r#enum) => {
353            error!(r#enum.enum_token.span(),
354                "enums are not supported"
355            );
356        },
357        | Data::Union(r#union) => {
358            error!(r#union.union_token.span(),
359                "unions are not supported"
360            );
361        },
362    };
363    let (mut iter1, mut iter2);
364    let fields: &mut dyn Iterator<Item = Field> = match fields {
365        | Fields::Unit => {
366            iter1 = iter::empty();
367            &mut iter1
368        },
369        | Fields::Unnamed(fields) => {
370            iter2 = fields.unnamed.into_iter();
371            &mut iter2
372        },
373        | Fields::Named(fields) => {
374            iter2 = fields.named.into_iter();
375            &mut iter2
376        },
377    };
378    let ref inherits: Ident = parse_quote! {
379        inherits
380    };
381    for (i, mut field) in fields.enumerate() {
382        let (path_to_InheritsTrait, span) =
383            match take(&mut field.attrs)
384                    .into_iter()
385                    .find_map(|attr| if attr.path.is_ident(inherits) { Some({
386                        let span = attr.span();
387                        attr.parse_args_with(Path::parse_mod_style)
388                            .map(|mut path| {
389                                let last =
390                                    path.segments
391                                        .iter_mut()
392                                        .last()
393                                        .expect("path has at least one segment")
394                                ;
395                                let ref Trait = last.ident;
396                                let InheritsTrait = Ident::new(&f!(
397                                    "__Inherits{Trait}__"
398                                ), span);
399                                *last = parse_quote! {
400                                    #InheritsTrait
401                                };
402                                (path, span)
403                            })
404                    })} else {
405                        None
406                    })
407            {
408                | None => continue,
409                | Some(Err(err)) => return err.to_compile_error().into(),
410                | Some(Ok(inner)) => inner,
411            }
412        ;
413        let field_name =
414            if let Some(ref ident) = field.ident {
415                quote! {
416                    #ident
417                }
418            } else {
419                let i: Index = i.into();
420                quote! {
421                    #i
422                }
423            }
424        ;
425        let ref FieldType = field.ty;
426        let (impl_generics, ty_generics, where_clause) =
427            generics.split_for_impl()
428        ;
429        render! { span =>
430            impl #impl_generics #path_to_InheritsTrait
431                for #Struct #ty_generics
432            #where_clause
433            {
434                type __Parent__ = #FieldType;
435
436                #[inline]
437                fn __parent__ (self: &'_ Self)
438                  -> &'_ Self::__Parent__
439                {
440                    &self.#field_name
441                }
442
443                #[inline]
444                fn __parent_mut__ (self: &'_ mut Self)
445                  -> &'_ mut Self::__Parent__
446                {
447                    &mut self.#field_name
448                }
449            }
450        }
451    }
452    debug!("=> generates =>\n\n{}\n-------------------------\n", ret);
453    ret
454}