bevy_dioxus_macro 0.1.1

Write cross-platform application with React-like declarative UI framework and scalable ECS architecture all in Rust.
Documentation
#[macro_use]
extern crate lazy_static;
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::{format_ident, quote};
use std::sync::Mutex;
use syn::{parse_macro_input, DeriveInput};

lazy_static! {
    static ref DEPS: Mutex<Vec<String>> = Mutex::new(Default::default());
}

#[proc_macro_derive(GlobalState)]
pub fn global_atom(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    DEPS.lock().as_mut().unwrap().push(input.ident.to_string());

    let name = &input.ident;
    let atom_name = format_ident!("{}", &name.to_string().to_uppercase());

    let gen = quote! {
        static #atom_name: Atom<#name> = |_| #name::default();
    };

    gen.into()
}

#[proc_macro_derive(GlobalStatePlugin)]
pub fn derive_global_state_plugin(_input: TokenStream) -> TokenStream {
    let mut enum_inners = vec![];
    let mut handler_inners = vec![];
    let mut systems = vec![];
    let mut add_systems = vec![];

    for name in DEPS.lock().unwrap().iter() {
        let atom_name = format_ident!("{}", name.to_uppercase());
        let system_name = format_ident!("apply_{}", name.to_lowercase());
        let name = format_ident!("{}", name);

        let enum_inner = quote! { #name(#name) };
        let handler_inner = quote! { GlobalState::#name(x) => root.set(#atom_name.unique_id(), x) };
        let system = quote! {
            fn #system_name(
                query: Query<&#name, Changed<#name>>,
                vdom_tx: Res<Sender<VDomCommand<GlobalState>>>,
            ) {
                for x in query.iter() {
                    match vdom_tx.try_send(VDomCommand::GlobalState(GlobalState::#name(x.clone()))) {
                        Ok(()) => {}
                        Err(e) => match e {
                            TrySendError::Full(e) => {
                                error!(
                                    "Failed to send VDomCommand: channel is full: event: {:?}",
                                    e
                                );
                            }
                            TrySendError::Closed(e) => {
                                error!(
                                    "Failed to send VDomCommand: channel is closed: event: {:?}",
                                    e
                                );
                            }
                        },
                    }
                }
            }
        };
        let add_system = quote! {
            app.add_system(#system_name);
        };

        enum_inners.push(enum_inner);
        handler_inners.push(handler_inner);
        systems.push(system);
        add_systems.push(add_system);
    }

    let gen = quote! {
        use dioxus::fermi::{AtomRoot, Readable};
        use std::rc::Rc;

        #[derive(Debug)]
        enum GlobalState {
            #(#enum_inners),*
        }

        impl GlobalStateHandler for GlobalState {
            fn handler(self, root: Rc<AtomRoot>) {
                match self {
                    #(#handler_inners),*
                }
            }
        }

        impl Plugin for GlobalStatePlugin {
            fn build(&self, app: &mut App) {
                #(#add_systems)*;
            }
        }

        #(#systems)*;

    };

    gen.into()
}