ftswarm_macros 0.2.2

Procedural macros for the ftswarm crate
Documentation
use proc_macro::{TokenStream};
use proc_macro2::Ident;
use quote::quote;
use syn::{LitBool, Token};

struct ActorSwarmObject {
    typename: Ident,
    _comma: Token![,],
    digital: bool,
}

impl syn::parse::Parse for ActorSwarmObject {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let typename: Ident = input.parse()?;
        let _comma: Token![,] = input.parse()?;
        let normally_open: LitBool = input.parse()?;

        Ok(ActorSwarmObject {
            typename,
            _comma,
            digital: normally_open.value,
        })
    }
}

pub fn actor_swarm_object_impl(input: TokenStream) -> TokenStream {
    let ActorSwarmObject { typename, _comma: _, digital } = syn::parse_macro_input!(input as ActorSwarmObject);

    let impl_block = if digital {
        quote! {
            impl #typename {
                pub async fn set(&self, value: ValueState) -> Result<(), String> {
                    self.run_command(
                        RpcFunction::SetSpeed,
                        vec![Argument::Int(value.into())]
                    ).await.map(|_| ())
                }
            }
        }
    } else {
        quote! {
            impl #typename {
                pub async fn set(&self, value: i32) -> Result<(), String> {
                    let value = value.max(-255).min(255);

                    self.run_command(
                        RpcFunction::SetSpeed,
                        vec![Argument::Int(value as i64)]
                    ).await.map(|_| ())
                }
            }
        }
    };

    return quote! {
        #[derive(Clone, Updateable)]
        pub struct #typename {
            pub name: String,
            swarm: FtSwarm
        }

        impl_swarm_object!(#typename, ());

        impl NewSwarmObject<()> for #typename {
            default_new_swarm_object_impls!();

            fn new(name: &str, swarm: FtSwarm, _: ()) -> Box<Self> {
                Box::new(#typename {
                    name: name.to_string(),
                    swarm
                })
            }

            fn init(&mut self) -> impl Future<Output = ()> {
                async move {
                    self.run_command(
                        RpcFunction::SetActorType,
                        vec![Argument::ActorType(ActorType::#typename)]
                    ).await.unwrap();
                }
            }
        }

        #impl_block
    }.into()
}