ab_code_gen/
actor_messages.rs

1use proc_macro2::TokenStream;
2use syn::{Ident, Type};
3
4use crate::MessageHandlerMethod;
5
6pub struct MessageEnumVariant<'a> {
7    name: Ident,
8    parameters: Vec<(&'a Ident, &'a Type)>,
9    return_type: Option<&'a Type>,
10}
11
12pub struct MessageEnum<'a> {
13    pub name: Ident,
14    variants: Vec<MessageEnumVariant<'a>>,
15}
16
17impl MessageEnum<'_> {
18    pub fn new<'a>(
19        name: Ident,
20        handler_methods: &[MessageHandlerMethod<'a>],
21    ) -> syn::Result<MessageEnum<'a>> {
22        let mut message_variants = Vec::<MessageEnumVariant>::new();
23
24        for handler_method in handler_methods {
25            let message_variant = MessageEnumVariant::new(handler_method)?;
26            message_variants.push(message_variant);
27        }
28        Ok(MessageEnum {
29            name,
30            variants: message_variants,
31        })
32    }
33
34    pub fn generate(&self) -> syn::Result<TokenStream> {
35        let enum_name = &self.name;
36        let message_variants: Vec<_> = self.variants.iter().map(|m| m.generate()).collect();
37        for message_variant in message_variants.iter() {
38            if message_variant.is_err() {
39                return message_variant.clone();
40            }
41        }
42        let message_variants = message_variants.into_iter().map(|elem| elem.unwrap());
43        let message_enum = quote::quote! {
44            #[derive(Debug)]
45            pub enum #enum_name {
46                #(#message_variants),*
47            }
48        };
49        Ok(message_enum)
50    }
51}
52
53impl MessageEnumVariant<'_> {
54    fn new<'a>(handler_method: &MessageHandlerMethod<'a>) -> syn::Result<MessageEnumVariant<'a>> {
55        let parameters: Vec<(&Ident, &Type)> = handler_method.parameters.clone();
56        let name = handler_method.get_name_camel_case();
57
58        Ok(MessageEnumVariant {
59            name: name.clone(),
60            parameters,
61            return_type: handler_method.get_return_type(),
62        })
63    }
64
65    fn generate(&self) -> syn::Result<TokenStream> {
66        let variant_name = &self.name;
67        let parameters = self.parameters.iter().map(|(name, ty)| {
68            quote::quote! { #name: #ty }
69        });
70        // if there is a return type T then we must add a respond_to field with the type tokio::sync::oneshot::Sender<T>
71        let mut respond_to = TokenStream::new();
72        if let Some(ret_type) = self.return_type {
73            respond_to = quote::quote! {
74                respond_to: tokio::sync::oneshot::Sender<#ret_type>
75            };
76        }
77
78        let message_variant = quote::quote! {
79            #variant_name {
80                #(#parameters,)*
81                #respond_to
82            }
83        };
84        Ok(message_variant)
85    }
86}