1extern crate proc_macro;
4use darling::FromAttributes;
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::{parse_macro_input, Data, DeriveInput, Fields, Type};
8
9#[proc_macro_derive(Interface, attributes(interface))]
25pub fn derive_interface_polybox(input: TokenStream) -> TokenStream {
26 derive_interface(input, "::zestors::interface")
27}
28
29#[derive(darling::FromAttributes)]
30#[darling(attributes(interface))]
31struct InterfaceAttrs {
32 path: Option<syn::Path>,
33}
34
35fn derive_interface(input: TokenStream, base: &str) -> TokenStream {
36 let input = parse_macro_input!(input as DeriveInput);
37 let attrs = match InterfaceAttrs::from_attributes(&input.attrs) {
38 Ok(attrs) => attrs,
39 Err(err) => return err.write_errors().into(),
40 };
41 let enum_name = &input.ident;
42
43 let base_path: syn::Path = attrs.path.unwrap_or_else(|| syn::parse_str(base).unwrap());
44 let msg_path: syn::Path = base_path.clone();
45
46 let variants = match &input.data {
48 Data::Enum(data_enum) => &data_enum.variants,
49 _ => panic!("Interface derive can only be used on enums"),
50 };
51
52 let mut inner_types = Vec::new();
53 let mut try_from_matches = Vec::new();
54 let mut try_into_matches = Vec::new();
55 let mut into_matches = Vec::new();
56 let mut from_impls = Vec::new();
57
58 for variant in variants {
59 let variant_name = &variant.ident;
60
61 match &variant.fields {
62 Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
63 let field_type = &fields.unnamed[0].ty;
64
65 let inner_type = extract_inner_envelope_type(field_type)
66 .expect("Interface variants must be of type Envelope<T>");
67
68 inner_types.push(inner_type);
69
70 try_from_matches.push(quote! {
71 let envelope = match envelope.downcast::<#inner_type>() {
72 Ok(envelope) => return Ok(Self::#variant_name(envelope)),
73 Err(envelope) => envelope,
74 };
75 });
76
77 try_into_matches.push(quote! {
78 if id == std::any::TypeId::of::<#inner_type>() {
79 if let Self::#variant_name(envelope) = self {
80 let converted = unsafe {
82 std::mem::transmute_copy::<#base_path::Envelope<#inner_type>, #base_path::Envelope<I>>(&envelope)
83 };
84 std::mem::forget(envelope);
85 return Ok(converted);
86 }
87 }
88 });
89
90 into_matches.push(quote! {
91 Self::#variant_name(envelope) => #msg_path::AnyEnvelope::new::<#inner_type>(envelope),
92 });
93
94 from_impls.push(quote! {
95 impl From<#msg_path::Envelope<#inner_type>> for #enum_name {
96 fn from(envelope: #msg_path::Envelope<#inner_type>) -> Self {
97 Self::#variant_name(envelope)
98 }
99 }
100
101 impl TryInto<#msg_path::Envelope<#inner_type>> for #enum_name {
102 type Error = Self;
103
104 fn try_into(self) -> Result<#msg_path::Envelope<#inner_type>, Self> {
105 if let #enum_name::#variant_name(envelope) = self {
106 Ok(envelope)
107 } else {
108 Err(self)
109 }
110 }
111 }
112 });
113 }
114 _ => panic!("Interface derive only supports variants with a single unnamed field, e.g., A(Envelope<T>)"),
115 }
116 }
117
118 let expanded = quote! {
119 impl #msg_path::Interface for #enum_name {
120 fn try_from_dyn_envelope(envelope: #msg_path::AnyEnvelope) -> Result<Self, #msg_path::AnyEnvelope> {
121 #(#try_from_matches)*
122 Err(envelope)
123 }
124
125 fn into_dyn_envelope(self) -> #msg_path::AnyEnvelope {
133 match self {
134 #(#into_matches)*
135 }
136 }
137
138 type Set = (#(#inner_types,)*);
139 }
140
141
142 impl #msg_path::Message for #enum_name {
143 type Output = ();
144 type Resolver = ();
145 type Receipt = ();
146 }
147
148
149 impl From<#msg_path::Envelope<#enum_name>> for #enum_name {
150 fn from(envelope: #msg_path::Envelope<#enum_name>) -> Self {
151 envelope.msg
152 }
153 }
154
155 impl TryInto<#msg_path::Envelope<#enum_name>> for #enum_name {
156 type Error = Self;
157
158 fn try_into(self) -> Result<#msg_path::Envelope<#enum_name>, Self> {
159 Ok(#msg_path::Envelope::new(self, ()))
160 }
161 }
162
163 #(#from_impls)*
164 };
165
166 TokenStream::from(expanded)
167}
168
169#[proc_macro_derive(HandlerInterface, attributes(interface))]
173pub fn derive_actor_interface(input: TokenStream) -> TokenStream {
174 let input = parse_macro_input!(input as DeriveInput);
175 let enum_name = &input.ident;
176 let attrs = match InterfaceAttrs::from_attributes(&input.attrs) {
177 Ok(attrs) => attrs,
178 Err(err) => return err.write_errors().into(),
179 };
180
181 let variants = match &input.data {
183 Data::Enum(data_enum) => &data_enum.variants,
184 _ => panic!("HandlerInterface derive can only be used on enums"),
185 };
186
187 let base_path = attrs
188 .path
189 .unwrap_or_else(|| syn::parse_str("::zestors").unwrap());
190
191 let mut handle_matches = Vec::new();
192 let mut inner_types = Vec::new();
193
194 for variant in variants {
195 let variant_name = &variant.ident;
196
197 match &variant.fields {
198 Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
199 let field_type = &fields.unnamed[0].ty;
200
201 let inner_type = extract_inner_envelope_type(field_type)
202 .expect("HandlerInterface variants must be of type Envelope<T>");
203
204 handle_matches.push(quote! {
205 Self::#variant_name(envelope) => {
206 <T as #base_path::actor::Handle<#inner_type>>::handle(actor, state, envelope.msg, envelope.req).await
207 }
208 });
209 inner_types.push(inner_type);
210 }
211 _ => panic!("HandlerInterface derive only supports variants with a single unnamed field, e.g., A(Envelope<T>)"),
212 }
213 }
214
215 let expanded = quote! {
216 impl<T> #base_path::actor::HandlerInterface<T> for #enum_name
217 where
218 T: #base_path::actor::Handler + #( #base_path::actor::Handle<#inner_types> + )*
219 {
220 async fn handle_with(self, state: #base_path::actor::HandlerContext<'_, T>, actor: &mut T) -> Result<(), ::rootcause::Report> {
221 match self {
222 #(#handle_matches)*
223 }
224 }
225 }
226 };
227
228 TokenStream::from(expanded)
229}
230
231#[proc_macro_derive(Message, attributes(msg))]
250pub fn derive_message(input: TokenStream) -> TokenStream {
251 _derive_message(input, "::zestors::interface")
252}
253
254#[derive(darling::FromAttributes)]
255#[darling(attributes(msg))]
256struct MessageAttrs {
257 reply: Option<syn::Type>,
258 path: Option<syn::Path>,
259}
260
261fn _derive_message(input: TokenStream, base: &str) -> TokenStream {
262 let input = parse_macro_input!(input as DeriveInput);
263 let attrs = match MessageAttrs::from_attributes(&input.attrs) {
264 Ok(attrs) => attrs,
265 Err(err) => return err.write_errors().into(),
266 };
267 let name = &input.ident;
268
269 let base_path: syn::Path = attrs.path.unwrap_or_else(|| syn::parse_str(base).unwrap());
270 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
271
272 let expanded = if let Some(reply_type) = attrs.reply {
273 quote!(
274 impl #impl_generics #base_path::Message for #name #ty_generics #where_clause
275 {
276 type Output = #reply_type;
277 type Receipt = #base_path::Reply<#reply_type>;
278 type Resolver = #base_path::Request<#reply_type>;
279 }
280 )
281 } else {
282 quote!(
283 impl #impl_generics #base_path::Message for #name #ty_generics #where_clause
284 {
285 type Output = ();
286 type Resolver = ();
287 type Receipt = ();
288 }
289 )
290 };
291
292 TokenStream::from(expanded)
293}
294
295fn extract_inner_envelope_type(ty: &Type) -> Option<&Type> {
296 if let Type::Path(type_path) = ty {
297 let segment = type_path.path.segments.last()?;
298 if segment.ident == "Envelope" {
299 if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
300 if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
301 return Some(inner_ty);
302 }
303 }
304 }
305 }
306 None
307}