1use crate::{Stop, StopReason};
42
43pub struct FnStop<F> {
62 f: F,
63}
64
65impl<F> FnStop<F>
66where
67 F: Fn() -> bool + Send + Sync,
68{
69 #[inline]
73 pub fn new(f: F) -> Self {
74 Self { f }
75 }
76}
77
78impl<F> Stop for FnStop<F>
79where
80 F: Fn() -> bool + Send + Sync,
81{
82 #[inline]
83 fn check(&self) -> Result<(), StopReason> {
84 if (self.f)() {
85 Err(StopReason::Cancelled)
86 } else {
87 Ok(())
88 }
89 }
90
91 #[inline]
92 fn should_stop(&self) -> bool {
93 (self.f)()
94 }
95}
96
97impl<F: Clone> Clone for FnStop<F> {
98 fn clone(&self) -> Self {
99 Self { f: self.f.clone() }
100 }
101}
102
103impl<F: Copy> Copy for FnStop<F> {}
104
105impl<F> core::fmt::Debug for FnStop<F> {
106 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107 f.debug_struct("FnStop").finish_non_exhaustive()
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use core::sync::atomic::{AtomicBool, Ordering};
115
116 #[test]
117 fn fn_stop_basic() {
118 let flag = AtomicBool::new(false);
119 let stop = FnStop::new(|| flag.load(Ordering::Relaxed));
120
121 assert!(!stop.should_stop());
122 assert!(stop.check().is_ok());
123
124 flag.store(true, Ordering::Relaxed);
125
126 assert!(stop.should_stop());
127 assert_eq!(stop.check(), Err(StopReason::Cancelled));
128 }
129
130 #[test]
131 fn fn_stop_with_static() {
132 static FLAG: AtomicBool = AtomicBool::new(false);
133
134 let stop = FnStop::new(|| FLAG.load(Ordering::Relaxed));
135 assert!(!stop.should_stop());
136
137 FLAG.store(true, Ordering::Relaxed);
138 assert!(stop.should_stop());
139
140 FLAG.store(false, Ordering::Relaxed);
142 }
143
144 #[test]
145 fn fn_stop_always_true() {
146 let stop = FnStop::new(|| true);
147 assert!(stop.should_stop());
148 assert_eq!(stop.check(), Err(StopReason::Cancelled));
149 }
150
151 #[test]
152 fn fn_stop_always_false() {
153 let stop = FnStop::new(|| false);
154 assert!(!stop.should_stop());
155 assert!(stop.check().is_ok());
156 }
157
158 #[test]
159 fn fn_stop_is_send_sync() {
160 fn assert_send_sync<T: Send + Sync>() {}
161 assert_send_sync::<FnStop<fn() -> bool>>();
162 }
163
164 #[test]
165 fn fn_stop_clone() {
166 let stop: FnStop<fn() -> bool> = FnStop::new(|| false);
168 let stop2 = stop.clone();
169 assert!(!stop2.should_stop());
170 }
171}
172
173#[cfg(all(test, feature = "alloc"))]
174mod alloc_tests {
175 use super::*;
176
177 #[test]
178 fn fn_stop_debug() {
179 extern crate alloc;
180 let stop = FnStop::new(|| false);
181 let debug = alloc::format!("{:?}", stop);
182 assert!(debug.contains("FnStop"));
183 }
184}