use crate::store_impl::ActionOp;
use crate::{StoreError, StoreImpl};
use std::sync::{Arc, Weak};
pub trait Dispatcher<Action: Send + Clone>: Send {
fn dispatch(&self, action: Action) -> Result<(), StoreError>;
fn dispatch_thunk(&self, thunk: Box<dyn FnOnce(Box<dyn Dispatcher<Action>>) + Send>);
fn dispatch_task(&self, task: Box<dyn FnOnce() + Send>);
}
pub(crate) struct WeakDispatcher<State, Action>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + 'static,
{
store: Weak<StoreImpl<State, Action>>,
}
unsafe impl<State, Action> Send for WeakDispatcher<State, Action>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + 'static,
{
}
unsafe impl<State, Action> Sync for WeakDispatcher<State, Action>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + 'static,
{
}
impl<State, Action> WeakDispatcher<State, Action>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + 'static,
{
pub fn new(dispatcher: Arc<StoreImpl<State, Action>>) -> Self {
Self {
store: Arc::downgrade(&dispatcher),
}
}
}
impl<State, Action> Dispatcher<Action> for WeakDispatcher<State, Action>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + 'static,
{
fn dispatch(&self, action: Action) -> Result<(), StoreError> {
if let Some(store) = self.store.upgrade() {
store.dispatch(action)
} else {
Err(StoreError::DispatchError(
"Dispatcher has been dropped".to_string(),
))
}
}
fn dispatch_thunk(&self, thunk: Box<dyn FnOnce(Box<dyn Dispatcher<Action>>) + Send>) {
if let Some(store) = self.store.upgrade() {
store.dispatch_thunk(thunk);
} else {
#[cfg(feature = "store-log")]
eprintln!("Dispatcher has been dropped, cannot dispatch thunk");
}
}
fn dispatch_task(&self, task: Box<dyn FnOnce() + Send>) {
if let Some(store) = self.store.upgrade() {
store.dispatch_task(task);
} else {
#[cfg(feature = "store-log")]
eprintln!("Dispatcher has been dropped, cannot dispatch task");
}
}
}
impl<State, Action> Dispatcher<Action> for Arc<StoreImpl<State, Action>>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + 'static,
{
fn dispatch(&self, action: Action) -> Result<(), StoreError> {
let sender = self.dispatch_tx.lock().unwrap();
if let Some(tx) = sender.as_ref() {
match tx.send(ActionOp::Action(action)) {
Ok(_) => Ok(()),
Err(_e) => {
#[cfg(feature = "store-log")]
eprintln!("Failed to send action: {:?}", _e);
Err(StoreError::DispatchError(
"Failed to send action".to_string(),
))
}
}
} else {
Err(StoreError::DispatchError("Store is stopped".to_string()))
}
}
fn dispatch_thunk(&self, thunk: Box<dyn FnOnce(Box<dyn Dispatcher<Action>>) + Send>) {
let weak_dispatcher = Box::new(WeakDispatcher::new(self.clone()));
match self.pool.lock() {
Ok(pool) => {
if let Some(pool) = pool.as_ref() {
pool.execute(move || {
thunk(weak_dispatcher);
})
}
}
Err(_e) => {
#[cfg(feature = "store-log")]
eprintln!("Failed to lock pool: {}", _e);
}
}
}
fn dispatch_task(&self, task: Box<dyn FnOnce() + Send>) {
match self.pool.lock() {
Ok(pool) => {
if let Some(pool) = pool.as_ref() {
pool.execute(move || {
task();
})
}
}
Err(_e) => {
#[cfg(feature = "store-log")]
eprintln!("Failed to lock pool: {}", _e);
}
}
}
}