1use alloc::{boxed::Box, collections::BTreeMap, rc::Rc};
7use core::{
8 any::{Any, TypeId, type_name},
9 cell::RefCell,
10 fmt::Debug,
11 num::NonZeroUsize,
12};
13
14#[derive(Debug, Default, Clone)]
19pub struct Metadata(Box<MetadataInner>);
20
21#[derive(Debug, Default, Clone)]
25struct MetadataInner(BTreeMap<TypeId, Rc<dyn Any>>);
26
27impl MetadataInner {
28 #[allow(clippy::unwrap_used)]
32 pub fn try_get<T: 'static + Clone>(&self) -> Option<T> {
33 self.0
35 .get(&TypeId::of::<T>())
36 .map(|v| v.downcast_ref::<T>().unwrap())
37 .cloned()
38 }
39
40 pub fn insert<T: 'static + Clone>(&mut self, value: T) {
44 self.0.insert(TypeId::of::<T>(), Rc::new(value));
45 }
46}
47
48pub type BoxWatcher<T> = Box<dyn Fn(Context<T>) + 'static>;
50
51#[derive(Debug, Clone)]
53pub struct Context<T> {
54 value: T,
56 metadata: Metadata,
58}
59
60impl<T> Context<T> {
61 pub const fn new(value: T, metadata: Metadata) -> Self {
63 Self { value, metadata }
64 }
65
66 #[must_use]
68 pub fn with<V: Clone + 'static>(mut self, value: V) -> Self {
69 self.metadata = self.metadata.with(value);
70 self
71 }
72
73 pub fn into_value(self) -> T {
75 self.value
76 }
77
78 pub const fn value(&self) -> &T {
80 &self.value
81 }
82
83 pub const fn metadata(&self) -> &Metadata {
85 &self.metadata
86 }
87
88 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Context<U> {
90 Context::new(f(self.value), self.metadata)
91 }
92
93 pub fn as_ref(&self) -> Context<&T> {
95 Context::new(&self.value, self.metadata.clone())
96 }
97}
98
99impl<T> From<T> for Context<T> {
100 fn from(value: T) -> Self {
101 Self::new(value, Metadata::new())
102 }
103}
104
105#[must_use]
107pub trait WatcherGuard: 'static {}
108
109impl WatcherGuard for () {}
110
111impl<T1: WatcherGuard, T2: WatcherGuard> WatcherGuard for (T1, T2) {}
112
113#[derive(Debug)]
115pub struct OnDrop<F>(Option<F>)
116where
117 F: FnOnce();
118
119impl<F> OnDrop<F>
120where
121 F: FnOnce() + 'static,
122{
123 pub const fn new(f: F) -> Self {
125 Self(Some(f))
126 }
127
128 #[allow(clippy::needless_pass_by_value)]
130 pub fn attach(guard: impl WatcherGuard, f: F) -> impl WatcherGuard {
131 OnDrop::new(move || {
132 let _ = guard;
133 f();
134 })
135 }
136}
137
138#[allow(clippy::unwrap_used)]
139impl<F> Drop for OnDrop<F>
140where
141 F: FnOnce(),
142{
143 fn drop(&mut self) {
144 (self.0.take().unwrap())();
145 }
146}
147
148pub type BoxWatcherGuard = Box<dyn WatcherGuard>;
150
151impl WatcherGuard for Box<dyn WatcherGuard> {}
152
153impl WatcherGuard for Rc<dyn WatcherGuard> {}
154
155impl<F: FnOnce() + 'static> WatcherGuard for OnDrop<F> {}
156
157impl Metadata {
158 #[must_use]
160 pub fn new() -> Self {
161 Self::default()
162 }
163
164 #[must_use]
170 #[allow(clippy::expect_used)]
171 pub fn get<T: 'static + Clone>(&self) -> T {
172 self.try_get()
173 .expect("Value of requested type should be present in metadata")
174 }
175
176 #[must_use]
180 pub fn try_get<T: 'static + Clone>(&self) -> Option<T> {
181 self.0.try_get()
182 }
183
184 #[must_use]
188 pub fn with<T: 'static + Clone>(mut self, value: T) -> Self {
189 self.0.insert(value);
190 self
191 }
192
193 #[must_use]
195 pub fn is_empty(&self) -> bool {
196 self.0.0.is_empty()
197 }
198}
199
200pub(crate) type WatcherId = NonZeroUsize;
202
203#[derive(Debug)]
207pub struct WatcherManager<T> {
208 inner: Rc<RefCell<WatcherManagerInner<T>>>,
209}
210
211impl<T> Clone for WatcherManager<T> {
212 fn clone(&self) -> Self {
213 Self {
214 inner: self.inner.clone(),
215 }
216 }
217}
218
219impl<T> Default for WatcherManager<T> {
220 fn default() -> Self {
221 Self {
222 inner: Rc::default(),
223 }
224 }
225}
226
227impl<T: 'static> WatcherManager<T> {
228 #[must_use]
230 pub fn new() -> Self {
231 Self::default()
232 }
233
234 #[must_use]
236 pub fn is_empty(&self) -> bool {
237 self.inner.borrow().is_empty()
238 }
239
240 pub fn register(&self, watcher: impl Fn(Context<T>) + 'static) -> WatcherId {
242 self.inner.borrow_mut().register(watcher)
243 }
244
245 pub fn register_as_guard(
247 &self,
248 watcher: impl Fn(Context<T>) + 'static,
249 ) -> WatcherManagerGuard<T> {
250 let id = self.register(watcher);
251 let this = self.clone();
252 WatcherManagerGuard { manager: this, id }
253 }
254
255 pub fn notify(&self, ctx: impl Fn() -> Context<T>) {
257 let this = Rc::downgrade(&self.inner);
258 if let Some(this) = this.upgrade() {
259 this.borrow().notify(ctx);
260 }
261 }
262
263 pub fn clear(&self) {
265 self.inner.borrow_mut().map.clear();
266 }
267
268 pub fn cancel(&self, id: WatcherId) {
270 self.inner.borrow_mut().cancel(id);
271 }
272}
273
274#[must_use]
276#[derive(Debug)]
277pub struct WatcherManagerGuard<T: 'static> {
278 manager: WatcherManager<T>,
279 id: WatcherId,
280}
281
282impl<T> WatcherGuard for WatcherManagerGuard<T> {}
283
284impl<T: 'static> Drop for WatcherManagerGuard<T> {
285 fn drop(&mut self) {
286 self.manager.cancel(self.id);
287 }
288}
289
290struct WatcherManagerInner<T> {
294 id: WatcherId,
295 map: BTreeMap<WatcherId, BoxWatcher<T>>,
296}
297
298impl<T> Debug for WatcherManagerInner<T> {
299 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
300 f.write_str(type_name::<Self>())
301 }
302}
303
304impl<T> Default for WatcherManagerInner<T> {
305 fn default() -> Self {
306 Self {
307 id: WatcherId::MIN,
308 map: BTreeMap::new(),
309 }
310 }
311}
312
313impl<T: 'static> WatcherManagerInner<T> {
314 pub fn is_empty(&self) -> bool {
316 self.map.is_empty()
317 }
318
319 const fn assign(&mut self) -> WatcherId {
321 let id = self.id;
322 self.id = match self.id.checked_add(1) {
323 Some(id) => id,
324 None => panic!("`id` grows beyond `usize::MAX`"),
325 };
326 id
327 }
328
329 pub fn register(&mut self, watcher: impl Fn(Context<T>) + 'static) -> WatcherId {
331 let id = self.assign();
332 self.map.insert(id, Box::new(watcher));
333 id
334 }
335
336 pub fn notify(&self, ctx: impl Fn() -> Context<T>) {
338 for watcher in self.map.values() {
339 watcher(ctx());
340 }
341 }
342
343 pub fn cancel(&mut self, id: WatcherId) {
345 self.map.remove(&id);
346 }
347}