disrupt_rs/event_handler.rs
1use crate::Sequence;
2
3/// Trait for processing events on consumer threads.
4///
5/// This is used by `handle_events_with` so handlers can be either closures or dedicated structs,
6/// without introducing dynamic dispatch.
7pub trait EventHandler<E>: Send {
8 /// Called for each published event.
9 fn on_event(&mut self, event: &E, sequence: Sequence, end_of_batch: bool);
10}
11
12/// A handler that forwards events to two handlers in sequence.
13#[derive(Debug, Clone, Default)]
14pub struct HandlerChain<H1, H2> {
15 first: H1,
16 second: H2,
17}
18
19impl<H1, H2> HandlerChain<H1, H2> {
20 /// Create a new chained handler.
21 #[inline]
22 pub fn new(first: H1, second: H2) -> Self {
23 Self { first, second }
24 }
25}
26
27impl<E, H1, H2> EventHandler<E> for HandlerChain<H1, H2>
28where
29 H1: EventHandler<E>,
30 H2: EventHandler<E>,
31{
32 #[inline]
33 fn on_event(&mut self, event: &E, sequence: Sequence, end_of_batch: bool) {
34 self.first.on_event(event, sequence, end_of_batch);
35 self.second.on_event(event, sequence, end_of_batch);
36 }
37}
38
39/// Extension trait for chaining event handlers together.
40pub trait EventHandlerChainExt<E>: EventHandler<E> + Sized {
41 /// Chain this handler with another handler, invoking both in order.
42 #[inline]
43 fn chain<H>(self, other: H) -> HandlerChain<Self, H>
44 where
45 H: EventHandler<E>,
46 {
47 HandlerChain::new(self, other)
48 }
49}
50
51impl<E, T> EventHandlerChainExt<E> for T where T: EventHandler<E> + Sized {}
52
53impl<E, F> EventHandler<E> for F
54where
55 F: FnMut(&E, Sequence, bool) + Send,
56{
57 #[inline]
58 fn on_event(&mut self, event: &E, sequence: Sequence, end_of_batch: bool) {
59 (self)(event, sequence, end_of_batch)
60 }
61}
62
63/// Trait for processing events with a separate mutable state value.
64///
65/// This is used by `handle_events_and_state_with` so handlers can be closures or dedicated structs,
66/// without introducing dynamic dispatch.
67///
68/// # Why a separate state value?
69///
70/// Consumer threads are started with `std::thread::spawn`, which requires that anything moved into
71/// the spawned thread is `Send`. That means the *handler* must be `Send`.
72///
73/// However, sometimes you want per-consumer state that is *thread-scoped* and therefore does not
74/// need to be `Send` (for example, `Rc`, `RefCell`, or other single-threaded arenas/allocators).
75/// You cannot store such a `!Send` value inside the handler struct itself, because then the handler
76/// becomes `!Send` and cannot be moved into the consumer thread.
77///
78/// `handle_events_and_state_with` takes an `initialize_state` closure (which *is* `Send`) and calls
79/// it **inside** the consumer thread after it starts, so the produced state can safely be `!Send`
80/// as long as it never leaves that thread.
81///
82/// ## Example: `Rc<RefCell<_>>` state
83/// ```no_run
84/// use std::{cell::RefCell, rc::Rc};
85///
86/// use disrupt_rs::{build_single_producer, BusySpin, Producer, Sequence};
87///
88/// #[derive(Default)]
89/// struct State {
90/// // `Rc` is `!Send`, so `State` is `!Send` too.
91/// counter: Rc<RefCell<u64>>,
92/// }
93///
94/// #[derive(Default)]
95/// struct Event {
96/// value: u64,
97/// }
98///
99/// let mut producer = build_single_producer(64, Event::default, BusySpin)
100/// .handle_events_and_state_with(
101/// |state: &mut State, _event: &Event, _seq: Sequence, _end: bool| {
102/// *state.counter.borrow_mut() += 1;
103/// },
104/// State::default, // constructed inside the consumer thread
105/// )
106/// .build();
107///
108/// producer.publish(|e| e.value = 123);
109/// drop(producer);
110/// ```
111pub trait EventHandlerWithState<E, S>: Send {
112 /// Called for each published event with mutable access to the state.
113 fn on_event(&mut self, state: &mut S, event: &E, sequence: Sequence, end_of_batch: bool);
114}
115
116impl<E, S, F> EventHandlerWithState<E, S> for F
117where
118 F: FnMut(&mut S, &E, Sequence, bool) + Send,
119{
120 #[inline]
121 fn on_event(&mut self, state: &mut S, event: &E, sequence: Sequence, end_of_batch: bool) {
122 (self)(state, event, sequence, end_of_batch)
123 }
124}