1use proc_macro::TokenStream;
4use quote::quote;
5use syn::*;
6
7#[proc_macro_derive(Baton)]
35pub fn derive_baton(input: TokenStream) -> TokenStream {
36 let input = parse_macro_input!(input as DeriveInput);
37
38 let base_name = input.ident;
40 let vis = input.vis;
41
42 let send_name = syn::Ident::new(&format!("{}Send", base_name), base_name.span());
44 let recv_name = syn::Ident::new(&format!("{}Recv", base_name), base_name.span());
45
46 let fields = if let Data::Struct(data) = &input.data {
48 match &data.fields {
49 Fields::Named(fields) => &fields.named,
50 _ => panic!("Baton can only be derived for structs with named fields"),
51 }
52 } else {
53 panic!("Baton can only be derived for structs");
54 };
55
56 let send_fields = fields.iter().map(|f| {
58 let name = &f.ident;
59 let ty = &f.ty;
60 let vis = &f.vis;
61 quote! {
62 #vis #name: ::baton::Send<#ty>,
63 }
64 });
65
66 let recv_fields = fields.iter().map(|f| {
67 let name = &f.ident;
68 let ty = &f.ty;
69 let vis = &f.vis;
70 quote! {
71 #vis #name: ::baton::Recv<#ty>,
72 }
73 });
74
75 let baton_fn_fields = fields.iter().map(|f| {
77 let name = &f.ident;
78
79 quote! {
80 let #name = ::baton::channel(self.#name);
81 }
82 });
83
84 let baton_fn_return_send = fields.iter().map(|f| {
85 let name = &f.ident;
86 quote! {
87 #name: #name.0,
88 }
89 });
90
91 let baton_fn_return_recv = fields.iter().map(|f| {
92 let name = &f.ident;
93 quote! {
94 #name: #name.1,
95 }
96 });
97
98 let expanded = quote! {
100 #[derive(Clone)]
101 #vis struct #send_name {
102 #(#send_fields)*
103 }
104
105 #[derive(Clone)]
106 #vis struct #recv_name {
107 #(#recv_fields)*
108 }
109
110 impl #base_name {
111 pub fn baton(self) -> (#send_name, #recv_name) {
112 #(#baton_fn_fields)*
113
114 (
115 #send_name {
116 #(#baton_fn_return_send)*
117 },
118 #recv_name {
119 #(#baton_fn_return_recv)*
120 }
121 )
122 }
123 }
124 };
125
126 TokenStream::from(expanded)
127}