use brisk_it::generator::{Generator, Result};
#[derive(Default)]
pub(super) struct Machine {}
impl Generator for Machine {
fn generate(
&self,
input: brisk_it::component::ComponentInput,
manager: &brisk_it::generator::Manager,
) -> Result<proc_macro2::TokenStream> {
let visibility = input.visibility.clone();
let state_info = crate::state::ParsedState::parse(input, manager)?;
let event_dispatcher = quote::format_ident!("{}EventDispatcher", state_info.id);
let event_manager = quote::format_ident!("{}EventManager", state_info.id);
let machine_holder = quote::format_ident!("{}Holder", state_info.id);
let initial_states = state_info.initialise_states(true).1;
let events_callbacks_args = match state_info.properties {
Some(_) => quote::quote! { &m.properties },
None => proc_macro2::TokenStream::new(),
};
let events_callbacks = state_info.events().into_iter().map(|ec| {
quote::quote! {
pub fn #ec(&self)
{
self.sender.send(Box::new(|m| m.state.borrow_mut().#ec(m.event_dispatcher(), #events_callbacks_args))).unwrap();
if let Some(cb) = &self.after_dispatching_event
{
cb();
}
}
}
});
let states = state_info.generate(&crate::state::GenerationInfo {
visibility: visibility.clone(),
event_dispatcher: event_dispatcher.clone(),
})?;
let id = state_info.id;
let machine_id = quote::format_ident!("{}Machine", id);
let mut fields = Vec::<proc_macro2::TokenStream>::new();
let create_function: proc_macro2::TokenStream;
if let Some(properties) = state_info.properties {
fields.push(quote::quote! { properties: #properties, });
create_function = quote::quote! {
pub fn create(super_properties: #properties) -> Self
{
let (sender, receiver) = std::sync::mpsc::channel::<Box<dyn Fn(&#machine_id) + Send + 'static>>();
let properties = super_properties;
Self {
#initial_states
properties,
receiver,
event_dispatcher: #event_dispatcher
{
sender,
after_dispatching_event: None
},
after_processing_events: None,
}
}
}
} else {
create_function = quote::quote! {
pub fn create() -> Self
{
let (sender, receiver) = std::sync::mpsc::channel::<Box<dyn Fn(&#machine_id) + Send + 'static>>();
Self {
#initial_states,
receiver,
event_dispatcher: #event_dispatcher
{
sender,
after_dispatching_event: None
},
after_processing_events: None
}
}
}
}
Ok(quote::quote! {
#states
#visibility struct #machine_id
{
state: std::cell::RefCell<#id>,
#(#fields)*
event_dispatcher: #event_dispatcher,
receiver: std::sync::mpsc::Receiver<Box<dyn Fn(&#machine_id) + Send + 'static>>,
after_processing_events: Option<Box<dyn Fn()>>,
}
enum #machine_holder<'a>
{
RefCell(&'a std::cell::RefCell<#machine_id>),
RwLock(&'a std::sync::RwLock<#machine_id>)
}
impl<'a> From<&'a std::cell::RefCell<#machine_id>> for #machine_holder<'a> {
fn from(value: &'a std::cell::RefCell<#machine_id>) -> Self {
Self::RefCell(value)
}
}
impl<'a> From<&'a std::sync::RwLock<#machine_id>> for #machine_holder<'a> {
fn from(value: &'a std::sync::RwLock<#machine_id>) -> Self {
Self::RwLock(value)
}
}
impl #machine_id
{
#create_function
pub fn after_processing_events(&mut self, cb: impl Fn() + 'static)
{
self.after_processing_events = Some(Box::new(cb));
}
pub fn after_dispatching_event(&mut self, cb: impl Fn() + Send + Sync + 'static)
{
self.event_dispatcher.after_dispatching_event = Some(std::sync::Arc::new(cb));
}
pub fn event_dispatcher(&self) -> &#event_dispatcher
{
&self.event_dispatcher
}
pub fn process_events(&mut self)
{
let mut processed_event = false;
while let Ok(evt) = self.receiver.try_recv()
{
processed_event = true;
evt(self);
}
if processed_event
{
if let Some(cb) = &self.after_processing_events
{
cb();
}
}
}
pub fn start_events<'a>(machine: impl Into<#machine_holder<'a>>) -> #event_manager<'a> {
let machine = machine.into();
let event_dispatcher = match machine
{
#machine_holder::RefCell(machine) => machine.borrow().event_dispatcher().clone(),
#machine_holder::RwLock(machine) => machine.read().unwrap().event_dispatcher().clone(),
};
#event_manager {
event_dispatcher,
machine,
}
}
pub fn borrow_state<'a>(&'a self) -> std::cell::Ref<'a, Main> {
self.state.borrow()
}
}
#[derive(Clone)]
#visibility struct #event_dispatcher
{
sender: std::sync::mpsc::Sender<Box<dyn Fn(&#machine_id) + Send + 'static>>,
after_dispatching_event: Option<std::sync::Arc<dyn Fn() + Send + Sync + 'static>>,
}
impl #event_dispatcher
{
#(#events_callbacks)*
}
#visibility struct #event_manager<'a> {
event_dispatcher: #event_dispatcher,
machine: #machine_holder<'a>,
}
impl<'a> std::ops::Deref for #event_manager<'a> {
type Target = #event_dispatcher;
fn deref(&self) -> &Self::Target {
&self.event_dispatcher
}
}
impl<'a> Drop for #event_manager<'a> {
fn drop(&mut self) {
match self.machine
{
#machine_holder::RefCell(machine) => machine.borrow_mut().process_events(),
#machine_holder::RwLock(machine) => machine.write().unwrap().process_events(),
}
}
}
})
}
fn boxed_clone(&self) -> Box<dyn Generator> {
Box::new(Self {})
}
}