polybox-codegen 0.0.1

Message-passing abstractions to make working with channels and actors a more seamless experience
Documentation
use proc_macro2::TokenStream;
use syn::{parse2, Error, Item, Type};

pub fn derive_handler(item: TokenStream) -> Result<TokenStream, Error> {
    let (ident, generics, attrs) = match parse2::<Item>(item)? {
        Item::Enum(item) => (item.ident, item.generics, item.attrs),
        Item::Struct(item) => (item.ident, item.generics, item.attrs),
        Item::Union(item) => (item.ident, item.generics, item.attrs),
        item => Err(Error::new_spanned(item, "Must be an Enum, Struct or Union"))?,
    };

    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let Some(state) = attrs.iter().find(|attr| attr.path.is_ident("state")) else {
        return Err(Error::new_spanned(ident, "No #[state(..)] attribute found"))?
    };
    let state = state.parse_args::<Type>()?;

    Ok(quote! {
        #[::polybox::export::async_trait]
        impl #impl_generics ::polybox::handler::Handler for #ident #ty_generics #where_clause
        {
            type State = #state;
            type Exception = ::polybox::export::Report;
            type Stop = ();
            type Exit = Result<Self, ::polybox::export::Report>;

            async fn handle_exit(
                self,
                state: &mut Self::State,
                reason: Result<Self::Stop, Self::Exception>,
            ) -> ::polybox::handler::ExitFlow<Self> {
                match reason {
                    Ok(()) => ::polybox::handler::ExitFlow::Exit(Ok(self)),
                    Err(exception) => ::polybox::handler::ExitFlow::Exit(Err(exception))
                }
            }

            async fn handle_event(
                &mut self,
                state: &mut Self::State,
                event: ::polybox::handler::Event
            ) -> ::polybox::handler::HandlerResult<Self> {
                match event {
                    ::polybox::handler::Event::Halted => {
                        state.close();
                        Ok(::polybox::handler::Flow::Continue)
                    }
                    ::polybox::handler::Event::ClosedAndEmpty => Ok(::polybox::handler::Flow::Stop(())),
                    ::polybox::handler::Event::Dead => Ok(::polybox::handler::Flow::Stop(())),
                }
            }
        }
    })
}