guinea-core 0.13.3

guinea's core: actors, reducers, scopes and the event bus
Documentation
use once_cell::sync::Lazy;
use std::sync::RwLock;

pub mod addr;
pub mod cancel;
pub mod ctx;
pub mod envelope;
pub mod flow;

pub mod traits;

pub use addr::*;
pub use cancel::*;
pub use ctx::*;
pub use envelope::*;
pub use traits::*;

pub mod event_bus;

pub mod registry;
pub mod shape;

pub type UiTask = Box<dyn FnOnce() + Send>;

pub trait UiDispatcher: Send + Sync {
    fn init(&self);
    fn dispatch(&self, task: UiTask);
}

static UI_DISPATCHER: Lazy<RwLock<Option<Box<dyn UiDispatcher>>>> = Lazy::new(|| RwLock::new(None));

pub fn set_ui_dispatcher(dispatcher: impl UiDispatcher + 'static) {
    *UI_DISPATCHER.write().unwrap() = Some(Box::new(dispatcher));
}

#[derive(Clone)]
pub struct UiThreadToken(std::marker::PhantomData<*const ()>);

impl UiThreadToken {
    pub fn dangerously_create_token_unchecked() -> Self {
        Self(std::marker::PhantomData)
    }
}

pub fn invoke_on_ui<F>(f: F)
where
    F: FnOnce() + Send + 'static,
{
    #[cfg(feature = "test-utils")]
    {
        if let Err(f) = crate::executor::queue_ui(Box::new(f)) {
            crate::actor::event_bus::EventBus::queue_test_task(f);
        }
    }

    #[cfg(not(feature = "test-utils"))]
    {
        if let Some(dispatcher) = UI_DISPATCHER.read().unwrap().as_ref() {
            dispatcher.dispatch(Box::new(f));
        } else {
            panic!(
                "UiDispatcher not initialized! Call guinea_core::actor::set_ui_dispatcher at startup."
            );
        }
    }
}

/// Like [`invoke_on_ui`], but hands `f` back when there is no UI thread to
/// run it on yet.
pub fn try_invoke_on_ui<F>(f: F) -> Result<(), F>
where
    F: FnOnce() + Send + 'static,
{
    #[cfg(feature = "test-utils")]
    {
        if let Err(f) = crate::executor::queue_ui(Box::new(f)) {
            crate::actor::event_bus::EventBus::queue_test_task(f);
        }
        Ok(())
    }

    #[cfg(not(feature = "test-utils"))]
    {
        match UI_DISPATCHER.read().unwrap().as_ref() {
            Some(dispatcher) => {
                dispatcher.dispatch(Box::new(f));
                Ok(())
            }
            None => Err(f),
        }
    }
}

/// The name the trace gives `T`: its type and the module it sits in, without
/// the rest of the path or the generics.
pub fn short_type_name<T: ?Sized>() -> &'static str {
    let full = std::any::type_name::<T>();
    let raw = full.split('<').next().unwrap_or(full);
    let mut parts = raw.rsplitn(3, "::");
    let raw = match (parts.next(), parts.next()) {
        (Some(name), Some(ns)) => {
            let ns_start = raw.len() - ns.len() - name.len() - "::".len();
            &raw[ns_start..]
        }
        (Some(name), None) => name,
        _ => raw,
    };

    raw.trim_end_matches('>')
}