oxide_mvu/
emitter.rs

1//! Event emitter for embedding callbacks in Props.
2
3#[cfg(feature = "no_std")]
4use alloc::boxed::Box;
5
6use portable_atomic_util::Arc;
7use spin::Mutex;
8
9/// Event emitter that can be embedded in Props.
10///
11/// Clone this handle to create callbacks in your Props that can trigger
12/// events when invoked (e.g., by user interaction).
13///
14/// `Emitter` uses interior mutability via `Arc<Mutex<...>>`, making it
15/// cheap to clone (just an atomic reference count increment) and thread-safe.
16///
17/// # Example
18///
19/// ```rust
20/// use oxide_mvu::{Emitter, MvuLogic, Effect};
21///
22/// enum Event { Click }
23///
24/// #[derive(Clone)]
25/// struct Model { clicks: u32 }
26///
27/// struct Props {
28///     clicks: u32,
29///     on_click: Box<dyn Fn()>,
30/// }
31///
32/// struct MyApp;
33///
34/// impl MvuLogic<Event, Model, Props> for MyApp {
35///     fn init(&self, model: Model) -> (Model, Effect<Event>) {
36///         (model, Effect::none())
37///     }
38///
39///     fn update(&self, event: Event, model: &Model) -> (Model, Effect<Event>) {
40///         match event {
41///             Event::Click => {
42///                 let new_model = Model {
43///                     clicks: model.clicks + 1,
44///                     ..model.clone()
45///                 };
46///                 (new_model, Effect::none())
47///             }
48///         }
49///     }
50///
51///     fn view(&self, model: &Model, emitter: &Emitter<Event>) -> Props {
52///         let emitter = emitter.clone();
53///         Props {
54///             clicks: model.clicks,
55///             on_click: Box::new(move || {
56///                 emitter.emit(Event::Click);
57///             }),
58///         }
59///     }
60/// }
61/// ```
62#[allow(clippy::type_complexity)]
63pub struct Emitter<Event>(pub(crate) Arc<Mutex<Box<dyn FnMut(Event) + Send + 'static>>>);
64
65impl<Event> Clone for Emitter<Event> {
66    fn clone(&self) -> Self {
67        Self(self.0.clone())
68    }
69}
70
71impl<Event> Emitter<Event> {
72    /// Create a new emitter from a callback function.
73    ///
74    /// The callback will be invoked when [`emit`](Self::emit) is used.
75    pub fn new<F: FnMut(Event) + Send + 'static>(f: F) -> Self {
76        Self(Arc::new(Mutex::new(Box::new(f))))
77    }
78
79    /// Emit an event.
80    ///
81    /// This queues the event for processing by the runtime. Multiple threads
82    /// can safely call this method concurrently.
83    pub fn emit(&self, event: Event) {
84        let mut f = self.0.lock();
85        f(event);
86    }
87}