escher_derive/
lib.rs

1use proc_macro::{TokenStream};
2use quote::{quote, ToTokens};
3use syn::{parse_macro_input, DeriveInput};
4
5#[proc_macro_derive(Rebindable)]
6pub fn derive_rebindable(input: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(input as DeriveInput);
8
9    let name = input.ident;
10    let generics = input.generics;
11
12    let mut impl_params: Vec<Box<dyn ToTokens>> = vec![Box::new(quote! { 'a })];
13    let mut type_params: Vec<Box<dyn ToTokens>> = vec![];
14    let mut out_params: Vec<Box<dyn ToTokens>> = vec![];
15
16    for _ in generics.lifetimes() {
17        type_params.push(Box::new(quote! { '_ }));
18        out_params.push(Box::new(quote! { 'a }));
19    }
20
21    for ident in generics.type_params().map(|p| &p.ident) {
22        impl_params.push(Box::new(quote! { #ident: 'a }));
23        type_params.push(Box::new(ident.clone()));
24        out_params.push(Box::new(ident.clone()));
25    }
26
27    for param in generics.const_params() {
28        let ident = &param.ident;
29        let ty = &param.ty;
30        impl_params.push(Box::new(quote! { const #ident: #ty }));
31        type_params.push(Box::new(ident.clone()));
32        out_params.push(Box::new(ident.clone()));
33    }
34
35    TokenStream::from(quote! {
36        unsafe impl<#(#impl_params),*> escher::RebindTo<'a> for #name<#(#type_params),*> {
37           type Out = #name<#(#out_params),*>;
38        }
39    })
40}