spectacle_impl_tuples/
lib.rs

1//! Don't use this crate. It's intended for use in exactly one place: spectacle.
2//! It does exactly one thing, for spectacle. It is likely to break in other contexts.
3
4use proc_macro::TokenStream;
5use quote::{format_ident, quote};
6use syn::{
7    parse::{Parse, ParseStream, Result},
8    parse_macro_input,
9};
10
11struct UpTo {
12    value: usize,
13}
14
15impl Parse for UpTo {
16    fn parse(input: ParseStream) -> Result<Self> {
17        let lit: syn::LitInt = input.parse()?;
18        let value = lit.base10_parse::<usize>()?;
19        Ok(UpTo { value })
20    }
21}
22
23#[proc_macro]
24pub fn impl_tuples(tokens: TokenStream) -> TokenStream {
25    let up_to = parse_macro_input!(tokens as UpTo);
26
27    let mut out = quote! {};
28
29    for arity in 0..=up_to.value {
30        let t_n = (0..arity)
31            .map(|n| format_ident!("T{}", n))
32            .collect::<Vec<_>>();
33        let idx = (0..arity).map(syn::Index::from).collect::<Vec<_>>();
34
35        out = quote! {
36            #out
37
38            impl<#(#t_n),*> Introspect for (#(#t_n,)*)
39            where
40                #(
41                    #t_n: 'static + Introspect,
42                )*
43            {
44                fn introspect_from<F>(&self, breadcrumbs: Breadcrumbs, mut visit: F)
45                where
46                    F: FnMut(&Breadcrumbs, &dyn Any),
47                {
48                    visit(&breadcrumbs, self);
49
50                    #({
51                        let mut breadcrumbs = breadcrumbs.clone();
52                        breadcrumbs.push_back(Breadcrumb::TupleIndex(#idx));
53                        self.#idx.introspect_from(breadcrumbs, &mut visit);
54                    })*
55                }
56            }
57        }
58    }
59
60    // eprintln!("impl_tuples:\n{}", out);
61
62    out.into()
63}