use proc_macro::TokenStream;
use quote::quote;
use syn::*;
#[proc_macro_derive(Baton)]
pub fn derive_baton(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let base_name = input.ident;
let send_name = syn::Ident::new(&format!("{}Send", base_name), base_name.span());
let recv_name = syn::Ident::new(&format!("{}Recv", base_name), base_name.span());
let fields = if let Data::Struct(data) = &input.data {
match &data.fields {
Fields::Named(fields) => &fields.named,
_ => panic!("Baton can only be derived for structs with named fields"),
}
} else {
panic!("Baton can only be derived for structs");
};
let send_fields = fields.iter().map(|f| {
let name = &f.ident;
let ty = &f.ty;
let vis = &f.vis;
quote! {
#vis #name: ::baton::Send<#ty>,
}
});
let recv_fields = fields.iter().map(|f| {
let name = &f.ident;
let ty = &f.ty;
let vis = &f.vis;
quote! {
#vis #name: ::baton::Recv<#ty>,
}
});
let baton_fn_fields = fields.iter().map(|f| {
let name = &f.ident;
quote! {
let #name = ::baton::channel(self.#name);
}
});
let baton_fn_return_send = fields.iter().map(|f| {
let name = &f.ident;
quote! {
#name: #name.0,
}
});
let baton_fn_return_recv = fields.iter().map(|f| {
let name = &f.ident;
quote! {
#name: #name.1,
}
});
let expanded = quote! {
pub struct #send_name {
#(#send_fields)*
}
pub struct #recv_name {
#(#recv_fields)*
}
impl #base_name {
pub fn baton(self) -> (#send_name, #recv_name) {
#(#baton_fn_fields)*
(
#send_name {
#(#baton_fn_return_send)*
},
#recv_name {
#(#baton_fn_return_recv)*
}
)
}
}
};
TokenStream::from(expanded)
}