oxide_mvu/emitter.rs
1//! Event emitter for embedding callbacks in Props.
2
3use flume::Sender;
4
5/// Event emitter that can be embedded in Props.
6///
7/// Clone this handle to create callbacks in your Props that can trigger
8/// events when invoked (e.g., by user interaction).
9///
10/// `Emitter` wraps a lock-free channel sender, making it cheap to clone
11/// and thread-safe without any locking overhead.
12///
13/// # Example
14///
15/// ```rust
16/// use oxide_mvu::{Emitter, MvuLogic, Effect};
17///
18/// enum Event { Click }
19///
20/// #[derive(Clone)]
21/// struct Model { clicks: u32 }
22///
23/// struct Props {
24/// clicks: u32,
25/// on_click: Box<dyn Fn()>,
26/// }
27///
28/// struct MyApp;
29///
30/// impl MvuLogic<Event, Model, Props> for MyApp {
31/// fn init(&self, model: Model) -> (Model, Effect<Event>) {
32/// (model, Effect::none())
33/// }
34///
35/// fn update(&self, event: Event, model: &Model) -> (Model, Effect<Event>) {
36/// match event {
37/// Event::Click => {
38/// let new_model = Model {
39/// clicks: model.clicks + 1,
40/// ..model.clone()
41/// };
42/// (new_model, Effect::none())
43/// }
44/// }
45/// }
46///
47/// fn view(&self, model: &Model, emitter: &Emitter<Event>) -> Props {
48/// let emitter = emitter.clone();
49/// Props {
50/// clicks: model.clicks,
51/// on_click: Box::new(move || {
52/// emitter.emit(Event::Click);
53/// }),
54/// }
55/// }
56/// }
57/// ```
58pub struct Emitter<Event: Send>(pub(crate) Sender<Event>);
59
60impl<Event: Send> Clone for Emitter<Event> {
61 fn clone(&self) -> Self {
62 Self(self.0.clone())
63 }
64}
65
66impl<Event: Send> Emitter<Event> {
67 /// Create a new emitter from a channel sender.
68 pub(crate) fn new(sender: Sender<Event>) -> Self {
69 Self(sender)
70 }
71
72 /// Emit an event.
73 ///
74 /// This queues the event for processing by the runtime. Multiple threads
75 /// can safely call this method concurrently via the lock-free channel.
76 pub fn emit(&self, event: Event) {
77 self.0.send(event).ok();
78 }
79}