1use crate::{Stop, StopReason};
24
25#[derive(Debug, Clone, Copy)]
47pub struct OrStop<A, B> {
48 a: A,
49 b: B,
50}
51
52impl<A, B> OrStop<A, B> {
53 #[inline]
55 pub fn new(a: A, b: B) -> Self {
56 Self { a, b }
57 }
58
59 #[inline]
61 pub fn first(&self) -> &A {
62 &self.a
63 }
64
65 #[inline]
67 pub fn second(&self) -> &B {
68 &self.b
69 }
70
71 #[inline]
73 pub fn into_inner(self) -> (A, B) {
74 (self.a, self.b)
75 }
76}
77
78impl<A: Stop, B: Stop> Stop for OrStop<A, B> {
79 #[inline]
80 #[track_caller]
81 fn check(&self) -> Result<(), StopReason> {
82 self.a.check()?;
83 self.b.check()
84 }
85
86 #[inline]
87 #[track_caller]
88 fn should_stop(&self) -> bool {
89 self.a.should_stop() || self.b.should_stop()
90 }
91
92 #[inline]
95 fn may_stop(&self) -> bool {
96 self.a.may_stop() || self.b.may_stop()
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use crate::{StopSource, Unstoppable};
104
105 #[test]
106 fn or_stop_neither() {
107 let a = StopSource::new();
108 let b = StopSource::new();
109 let combined = OrStop::new(a.as_ref(), b.as_ref());
110
111 assert!(!combined.should_stop());
112 assert!(combined.check().is_ok());
113 }
114
115 #[test]
116 fn or_stop_first() {
117 let a = StopSource::new();
118 let b = StopSource::new();
119 let combined = OrStop::new(a.as_ref(), b.as_ref());
120
121 a.cancel();
122
123 assert!(combined.should_stop());
124 assert_eq!(combined.check(), Err(StopReason::Cancelled));
125 }
126
127 #[test]
128 fn or_stop_second() {
129 let a = StopSource::new();
130 let b = StopSource::new();
131 let combined = OrStop::new(a.as_ref(), b.as_ref());
132
133 b.cancel();
134
135 assert!(combined.should_stop());
136 assert_eq!(combined.check(), Err(StopReason::Cancelled));
137 }
138
139 #[test]
140 fn or_stop_both() {
141 let a = StopSource::new();
142 let b = StopSource::new();
143 let combined = OrStop::new(a.as_ref(), b.as_ref());
144
145 a.cancel();
146 b.cancel();
147
148 assert!(combined.should_stop());
149 }
150
151 #[test]
152 fn or_stop_chain() {
153 let a = StopSource::new();
154 let b = StopSource::new();
155 let c = StopSource::new();
156
157 let combined = OrStop::new(OrStop::new(a.as_ref(), b.as_ref()), c.as_ref());
158
159 assert!(!combined.should_stop());
160
161 c.cancel();
162 assert!(combined.should_stop());
163 }
164
165 #[test]
166 fn or_stop_with_unstoppable() {
167 let source = StopSource::new();
168 let combined = OrStop::new(Unstoppable, source.as_ref());
169
170 assert!(!combined.should_stop());
171
172 source.cancel();
173 assert!(combined.should_stop());
174 }
175
176 #[test]
177 fn or_stop_is_send_sync() {
178 fn assert_send_sync<T: Send + Sync>() {}
179 assert_send_sync::<OrStop<crate::StopRef<'_>, crate::StopRef<'_>>>();
180 }
181
182 #[test]
183 fn or_stop_accessors() {
184 let a = StopSource::new();
185 let b = StopSource::new();
186 let combined = OrStop::new(a.as_ref(), b.as_ref());
187
188 assert!(!combined.first().should_stop());
189 assert!(!combined.second().should_stop());
190
191 a.cancel();
192 assert!(combined.first().should_stop());
193
194 let (first, second) = combined.into_inner();
195 assert!(first.should_stop());
196 assert!(!second.should_stop());
197 }
198
199 #[test]
200 fn or_stop_ref_is_copy() {
201 let a = StopSource::new();
203 let b = StopSource::new();
204 let combined = OrStop::new(a.as_ref(), b.as_ref());
205 let combined2 = combined; a.cancel();
208 assert!(combined.should_stop()); assert!(combined2.should_stop());
210 }
211
212 #[test]
213 fn or_stop_is_copy() {
214 let a = StopSource::new();
215 let b = StopSource::new();
216 let combined = OrStop::new(a.as_ref(), b.as_ref());
217 let combined2 = combined; let _ = combined; assert!(!combined2.should_stop());
221 }
222
223 #[test]
224 fn may_stop_both_unstoppable() {
225 let combined = OrStop::new(Unstoppable, Unstoppable);
226 assert!(!combined.may_stop());
227 }
228
229 #[test]
230 fn may_stop_one_side() {
231 let source = StopSource::new();
232 let combined = OrStop::new(Unstoppable, source.as_ref());
233 assert!(combined.may_stop());
234 }
235
236 #[test]
237 fn may_stop_both_sides() {
238 let a = StopSource::new();
239 let b = StopSource::new();
240 let combined = OrStop::new(a.as_ref(), b.as_ref());
241 assert!(combined.may_stop());
242 }
243}