tokens/
single.rs

1use crate::{Callback, ChangeToken, DefaultChangeToken, Registration};
2use std::{any::Any, sync::Arc};
3
4/// Represents a [`ChangeToken`](crate::ChangeToken) that changes at most once.
5pub struct SingleChangeToken {
6    inner: DefaultChangeToken,
7}
8
9impl SingleChangeToken {
10    /// Initializes a new single change token.
11    pub fn new() -> Self {
12        Self::default()
13    }
14
15    /// Notifies any registered callbacks of a change.
16    ///
17    /// # Remarks
18    ///
19    /// Registered callbacks will be invoked exactly once. If this function is called more
20    /// than once, no action is performed.
21    pub fn notify(&self) {
22        self.inner.notify()
23    }
24}
25
26impl Default for SingleChangeToken {
27    fn default() -> Self {
28        Self {
29            inner: DefaultChangeToken::once(),
30        }
31    }
32}
33
34impl ChangeToken for SingleChangeToken {
35    fn changed(&self) -> bool {
36        self.inner.changed()
37    }
38
39    fn register(&self, callback: Callback, state: Option<Arc<dyn Any>>) -> Registration {
40        self.inner.register(callback, state)
41    }
42}
43
44unsafe impl Send for SingleChangeToken {}
45unsafe impl Sync for SingleChangeToken {}
46
47#[cfg(test)]
48mod tests {
49
50    use super::*;
51    use std::sync::{
52        atomic::{AtomicU8, Ordering},
53        Arc,
54    };
55
56    #[test]
57    fn single_change_token_should_be_unchanged() {
58        // arrange
59        let token = SingleChangeToken::default();
60
61        // act
62        let changed = token.changed();
63
64        // assert
65        assert_eq!(changed, false);
66    }
67
68    #[test]
69    fn single_change_token_should_be_changed() {
70        // arrange
71        let token = SingleChangeToken::default();
72
73        // act
74        token.notify();
75
76        // assert
77        assert_eq!(token.changed(), true);
78    }
79
80    #[test]
81    fn single_change_token_should_invoke_callback() {
82        // arrange
83        let counter = Arc::new(AtomicU8::default());
84        let token = SingleChangeToken::default();
85        let _registration = token.register(
86            Box::new(|state| {
87                state.unwrap().downcast_ref::<AtomicU8>().unwrap().fetch_add(1, Ordering::SeqCst);
88            }),
89            Some(counter.clone()),
90        );
91
92        // act
93        token.notify();
94
95        // assert
96        assert_eq!(counter.load(Ordering::SeqCst), 1);
97    }
98
99    #[test]
100    fn single_change_token_should_not_invoke_callback_more_than_once() {
101        // arrange
102        let counter = Arc::new(AtomicU8::default());
103        let token = SingleChangeToken::default();
104        let _registration = token.register(
105            Box::new(|state| {
106                state.unwrap().downcast_ref::<AtomicU8>().unwrap().fetch_add(1, Ordering::SeqCst);
107            }),
108            Some(counter.clone()),
109        );
110        token.notify();
111
112        // act
113        token.notify();
114
115        // assert
116        assert_eq!(counter.load(Ordering::SeqCst), 1);
117    }
118}