par_iter/iter/
panic_fuse.rs

1use std::{
2    sync::atomic::{AtomicBool, Ordering},
3    thread,
4};
5
6use super::{plumbing::*, *};
7
8/// `PanicFuse` is an adaptor that wraps an iterator with a fuse in case
9/// of panics, to halt all threads as soon as possible.
10///
11/// This struct is created by the [`panic_fuse()`] method on
12/// [`ParallelIterator`]
13///
14/// [`panic_fuse()`]: trait.ParallelIterator.html#method.panic_fuse
15/// [`ParallelIterator`]: trait.ParallelIterator.html
16#[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/// Helper that sets a bool to `true` if dropped while unwinding.
23#[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    /// Creates a new `PanicFuse` iterator.
47    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
126/// ////////////////////////////////////////////////////////////////////////
127/// Producer implementation
128
129struct 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
228/// ////////////////////////////////////////////////////////////////////////
229/// Consumer implementation
230
231struct 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}