1use crate::{Callback, ChangeToken, DefaultChangeToken, Registration};
2use std::{any::Any, sync::Arc};
3
4pub struct SingleChangeToken {
6 inner: DefaultChangeToken,
7}
8
9impl SingleChangeToken {
10 pub fn new() -> Self {
12 Self::default()
13 }
14
15 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 let token = SingleChangeToken::default();
60
61 let changed = token.changed();
63
64 assert_eq!(changed, false);
66 }
67
68 #[test]
69 fn single_change_token_should_be_changed() {
70 let token = SingleChangeToken::default();
72
73 token.notify();
75
76 assert_eq!(token.changed(), true);
78 }
79
80 #[test]
81 fn single_change_token_should_invoke_callback() {
82 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 token.notify();
94
95 assert_eq!(counter.load(Ordering::SeqCst), 1);
97 }
98
99 #[test]
100 fn single_change_token_should_not_invoke_callback_more_than_once() {
101 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 token.notify();
114
115 assert_eq!(counter.load(Ordering::SeqCst), 1);
117 }
118}