cranpose_services/
inbox.rs1use std::{
10 collections::VecDeque,
11 sync::{Arc, Mutex, PoisonError},
12};
13
14type Observer<T> = Arc<dyn Fn(T) + Send + Sync>;
15
16struct State<T> {
17 observers: Vec<(u64, Observer<T>)>,
18 backlog: VecDeque<T>,
19 next_id: u64,
20}
21
22pub(crate) struct Inbox<T> {
24 name: &'static str,
26 state: Mutex<State<T>>,
27}
28
29impl<T: Clone + Send + 'static> Inbox<T> {
30 pub(crate) const fn new(name: &'static str) -> Self {
31 Self {
32 name,
33 state: Mutex::new(State {
34 observers: Vec::new(),
35 backlog: VecDeque::new(),
36 next_id: 0,
37 }),
38 }
39 }
40
41 fn state(&self) -> std::sync::MutexGuard<'_, State<T>> {
42 self.state.lock().unwrap_or_else(PoisonError::into_inner)
43 }
44
45 pub(crate) fn observe(
47 &'static self,
48 observer: impl Fn(T) + Send + Sync + 'static,
49 ) -> InboxObserver {
50 let observer: Observer<T> = Arc::new(observer);
51 let (id, replay) = {
52 let mut state = self.state();
53 let id = state.next_id;
54 state.next_id += 1;
55 state.observers.push((id, Arc::clone(&observer)));
56 (id, std::mem::take(&mut state.backlog))
57 };
58 log::info!(
59 "{}: observer {id} registered, replays {} item(s)",
60 self.name,
61 replay.len()
62 );
63 for item in replay {
64 observer(item);
65 }
66 InboxObserver { id, inbox: self }
67 }
68
69 pub(crate) fn publish(&self, item: T) {
71 let observers: Vec<Observer<T>> = {
72 let mut state = self.state();
73 if state.observers.is_empty() {
74 state.backlog.push_back(item);
75 log::info!("{}: no observer yet, the item waits", self.name);
76 return;
77 }
78 state
79 .observers
80 .iter()
81 .map(|(_, observer)| Arc::clone(observer))
82 .collect()
83 };
84 log::info!(
85 "{}: an item goes to {} observer(s)",
86 self.name,
87 observers.len()
88 );
89 for observer in observers {
90 observer(item.clone());
91 }
92 }
93
94 pub(crate) fn clear(&self) {
96 self.state().backlog.clear();
97 }
98}
99
100trait Unobserve: Sync {
101 fn unobserve(&self, id: u64);
102}
103
104impl<T: Send> Unobserve for Inbox<T> {
105 fn unobserve(&self, id: u64) {
106 self.state
107 .lock()
108 .unwrap_or_else(PoisonError::into_inner)
109 .observers
110 .retain(|(existing, _)| *existing != id);
111 }
112}
113
114pub struct InboxObserver {
117 id: u64,
118 inbox: &'static dyn Unobserve,
119}
120
121impl Drop for InboxObserver {
122 fn drop(&mut self) {
123 self.inbox.unobserve(self.id);
124 }
125}