tokens/token.rs
1use std::{any::Any, ops::Deref, sync::Arc};
2
3/// Represents the state associated with a change notification.
4pub type State = Option<Arc<dyn Any + Send + Sync>>;
5
6/// Represents a change notification callback.
7pub type Callback = Box<dyn Fn(State) + Send + Sync>;
8
9type CallbackRef = Arc<dyn Fn(State) + Send + Sync>;
10
11/// Represents a [`ChangeToken`](crate::ChangeToken) registration.
12///
13/// # Remarks
14///
15/// When the registration is dropped, the underlying callback is unregistered.
16pub struct Registration(#[allow(dead_code)] CallbackRef);
17
18impl Registration {
19 /// Initializes a new change token registration.
20 #[inline]
21 pub fn new(callback: CallbackRef) -> Self {
22 Self(callback)
23 }
24
25 /// Initializes a new, empty change token registration.
26 #[inline]
27 pub fn none() -> Self {
28 Self::default()
29 }
30}
31
32impl Default for Registration {
33 #[inline]
34 fn default() -> Self {
35 Self(Arc::new(|_| {}))
36 }
37}
38
39/// Propagates notifications that a change has occurred.
40pub trait ChangeToken: Send + Sync {
41 /// Gets a value that indicates if a change has occurred.
42 fn changed(&self) -> bool;
43
44 /// Indicates if this token will proactively raise callbacks.
45 ///
46 /// # Remarks
47 ///
48 /// If `false`, the token consumer should expect for that any callback
49 /// specified in [`register`](ChangeToken::register) will be invoked
50 /// when a change occurs. If `false`, the token consumer must poll
51 /// [`changed`](ChangeToken::changed) to detect changes.
52 fn must_poll(&self) -> bool {
53 false
54 }
55
56 /// Registers for a callback that will be invoked when the token has changed.
57 ///
58 /// # Arguments
59 ///
60 /// * `callback` - The callback to invoke
61 /// * `state` - The optional [state](State) provided to the callback, if any
62 ///
63 /// # Returns
64 ///
65 /// An opaque change token [registration](Registration). When it
66 /// is dropped, the callback function is unregistered.
67 #[must_use]
68 fn register(&self, callback: Callback, state: State) -> Registration;
69}
70
71// this allows Box<dyn ChangeToken> to be used for T: ChangeToken
72impl ChangeToken for Box<dyn ChangeToken> {
73 #[inline]
74 fn changed(&self) -> bool {
75 self.deref().changed()
76 }
77
78 #[inline]
79 fn must_poll(&self) -> bool {
80 self.deref().must_poll()
81 }
82
83 #[inline]
84 fn register(&self, callback: Callback, state: State) -> Registration {
85 self.deref().register(callback, state)
86 }
87}