1use std::{
2 sync::atomic::{AtomicBool, Ordering},
3 thread,
4};
5
6use super::{plumbing::*, *};
7
8#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
17#[derive(Debug, Clone)]
18pub struct PanicFuse<I: ParallelIterator> {
19 base: I,
20}
21
22#[derive(Clone)]
24struct Fuse<'a>(&'a AtomicBool);
25
26impl<'a> Drop for Fuse<'a> {
27 #[inline]
28 fn drop(&mut self) {
29 if thread::panicking() {
30 self.0.store(true, Ordering::Relaxed);
31 }
32 }
33}
34
35impl<'a> Fuse<'a> {
36 #[inline]
37 fn panicked(&self) -> bool {
38 self.0.load(Ordering::Relaxed)
39 }
40}
41
42impl<I> PanicFuse<I>
43where
44 I: ParallelIterator,
45{
46 pub(super) fn new(base: I) -> PanicFuse<I> {
48 PanicFuse { base }
49 }
50}
51
52impl<I> ParallelIterator for PanicFuse<I>
53where
54 I: ParallelIterator,
55{
56 type Item = I::Item;
57
58 fn drive_unindexed<C>(self, consumer: C) -> C::Result
59 where
60 C: UnindexedConsumer<Self::Item>,
61 {
62 let panicked = AtomicBool::new(false);
63 let consumer1 = PanicFuseConsumer {
64 base: consumer,
65 fuse: Fuse(&panicked),
66 };
67 self.base.drive_unindexed(consumer1)
68 }
69
70 fn opt_len(&self) -> Option<usize> {
71 self.base.opt_len()
72 }
73}
74
75impl<I> IndexedParallelIterator for PanicFuse<I>
76where
77 I: IndexedParallelIterator,
78{
79 fn drive<C>(self, consumer: C) -> C::Result
80 where
81 C: Consumer<Self::Item>,
82 {
83 let panicked = AtomicBool::new(false);
84 let consumer1 = PanicFuseConsumer {
85 base: consumer,
86 fuse: Fuse(&panicked),
87 };
88 self.base.drive(consumer1)
89 }
90
91 fn len(&self) -> usize {
92 self.base.len()
93 }
94
95 fn with_producer<CB>(self, callback: CB) -> CB::Output
96 where
97 CB: ProducerCallback<Self::Item>,
98 {
99 return self.base.with_producer(Callback { callback });
100
101 struct Callback<CB> {
102 callback: CB,
103 }
104
105 impl<T, CB> ProducerCallback<T> for Callback<CB>
106 where
107 CB: ProducerCallback<T>,
108 {
109 type Output = CB::Output;
110
111 fn callback<P>(self, base: P) -> CB::Output
112 where
113 P: Producer<Item = T>,
114 {
115 let panicked = AtomicBool::new(false);
116 let producer = PanicFuseProducer {
117 base,
118 fuse: Fuse(&panicked),
119 };
120 self.callback.callback(producer)
121 }
122 }
123 }
124}
125
126struct PanicFuseProducer<'a, P> {
130 base: P,
131 fuse: Fuse<'a>,
132}
133
134impl<'a, P> Producer for PanicFuseProducer<'a, P>
135where
136 P: Producer,
137{
138 type IntoIter = PanicFuseIter<'a, P::IntoIter>;
139 type Item = P::Item;
140
141 fn into_iter(self) -> Self::IntoIter {
142 PanicFuseIter {
143 base: self.base.into_iter(),
144 fuse: self.fuse,
145 }
146 }
147
148 fn min_len(&self) -> usize {
149 self.base.min_len()
150 }
151
152 fn max_len(&self) -> usize {
153 self.base.max_len()
154 }
155
156 fn split_at(self, index: usize) -> (Self, Self) {
157 let (left, right) = self.base.split_at(index);
158 (
159 PanicFuseProducer {
160 base: left,
161 fuse: self.fuse.clone(),
162 },
163 PanicFuseProducer {
164 base: right,
165 fuse: self.fuse,
166 },
167 )
168 }
169
170 fn fold_with<G>(self, folder: G) -> G
171 where
172 G: Folder<Self::Item>,
173 {
174 let folder1 = PanicFuseFolder {
175 base: folder,
176 fuse: self.fuse,
177 };
178 self.base.fold_with(folder1).base
179 }
180}
181
182struct PanicFuseIter<'a, I> {
183 base: I,
184 fuse: Fuse<'a>,
185}
186
187impl<'a, I> Iterator for PanicFuseIter<'a, I>
188where
189 I: Iterator,
190{
191 type Item = I::Item;
192
193 fn next(&mut self) -> Option<Self::Item> {
194 if self.fuse.panicked() {
195 None
196 } else {
197 self.base.next()
198 }
199 }
200
201 fn size_hint(&self) -> (usize, Option<usize>) {
202 self.base.size_hint()
203 }
204}
205
206impl<'a, I> DoubleEndedIterator for PanicFuseIter<'a, I>
207where
208 I: DoubleEndedIterator,
209{
210 fn next_back(&mut self) -> Option<Self::Item> {
211 if self.fuse.panicked() {
212 None
213 } else {
214 self.base.next_back()
215 }
216 }
217}
218
219impl<'a, I> ExactSizeIterator for PanicFuseIter<'a, I>
220where
221 I: ExactSizeIterator,
222{
223 fn len(&self) -> usize {
224 self.base.len()
225 }
226}
227
228struct PanicFuseConsumer<'a, C> {
232 base: C,
233 fuse: Fuse<'a>,
234}
235
236impl<'a, T, C> Consumer<T> for PanicFuseConsumer<'a, C>
237where
238 C: Consumer<T>,
239{
240 type Folder = PanicFuseFolder<'a, C::Folder>;
241 type Reducer = PanicFuseReducer<'a, C::Reducer>;
242 type Result = C::Result;
243
244 fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
245 let (left, right, reducer) = self.base.split_at(index);
246 (
247 PanicFuseConsumer {
248 base: left,
249 fuse: self.fuse.clone(),
250 },
251 PanicFuseConsumer {
252 base: right,
253 fuse: self.fuse.clone(),
254 },
255 PanicFuseReducer {
256 base: reducer,
257 _fuse: self.fuse,
258 },
259 )
260 }
261
262 fn into_folder(self) -> Self::Folder {
263 PanicFuseFolder {
264 base: self.base.into_folder(),
265 fuse: self.fuse,
266 }
267 }
268
269 fn full(&self) -> bool {
270 self.fuse.panicked() || self.base.full()
271 }
272}
273
274impl<'a, T, C> UnindexedConsumer<T> for PanicFuseConsumer<'a, C>
275where
276 C: UnindexedConsumer<T>,
277{
278 fn split_off_left(&self) -> Self {
279 PanicFuseConsumer {
280 base: self.base.split_off_left(),
281 fuse: self.fuse.clone(),
282 }
283 }
284
285 fn to_reducer(&self) -> Self::Reducer {
286 PanicFuseReducer {
287 base: self.base.to_reducer(),
288 _fuse: self.fuse.clone(),
289 }
290 }
291}
292
293struct PanicFuseFolder<'a, C> {
294 base: C,
295 fuse: Fuse<'a>,
296}
297
298impl<'a, T, C> Folder<T> for PanicFuseFolder<'a, C>
299where
300 C: Folder<T>,
301{
302 type Result = C::Result;
303
304 fn consume(mut self, item: T) -> Self {
305 self.base = self.base.consume(item);
306 self
307 }
308
309 fn consume_iter<I>(mut self, iter: I) -> Self
310 where
311 I: IntoIterator<Item = T>,
312 {
313 fn cool<'a, T>(fuse: &'a Fuse<'_>) -> impl Fn(&T) -> bool + 'a {
314 move |_| !fuse.panicked()
315 }
316
317 self.base = {
318 let fuse = &self.fuse;
319 let iter = iter.into_iter().take_while(cool(fuse));
320 self.base.consume_iter(iter)
321 };
322 self
323 }
324
325 fn complete(self) -> C::Result {
326 self.base.complete()
327 }
328
329 fn full(&self) -> bool {
330 self.fuse.panicked() || self.base.full()
331 }
332}
333
334struct PanicFuseReducer<'a, C> {
335 base: C,
336 _fuse: Fuse<'a>,
337}
338
339impl<'a, T, C> Reducer<T> for PanicFuseReducer<'a, C>
340where
341 C: Reducer<T>,
342{
343 fn reduce(self, left: T, right: T) -> T {
344 self.base.reduce(left, right)
345 }
346}