Skip to main content

paralight/iter/
detail.rs

1// Copyright 2024-2026 The Paralight Authors
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Implementation details of iterator adaptors.
10
11use super::{
12    Accumulator, ExactSizeAccumulator, ParallelAdaptor, ParallelAdaptorDescriptor, ParallelIterator,
13};
14use crossbeam_utils::CachePadded;
15use scopeguard::ScopeGuard;
16use std::cmp::Ordering;
17use std::iter::{Product, Sum};
18use std::marker::PhantomData;
19use std::ops::ControlFlow;
20#[cfg(feature = "nightly")]
21use std::ops::{FromResidual, Residual, Try};
22use std::sync::atomic::AtomicBool;
23
24/// A fuse is an atomic object that starts unset and can transition once to the
25/// set state.
26///
27/// Under the hood, this contains an atomic boolean aligned to a cache line to
28/// avoid any risk of false sharing performance overhead.
29pub struct Fuse(CachePadded<AtomicBool>);
30
31/// State of a [`Fuse`].
32#[derive(PartialEq, Eq)]
33enum FuseState {
34    Unset,
35    Set,
36}
37
38impl Fuse {
39    /// Creates a new fuse in the [`Unset`](FuseState::Unset) state.
40    pub fn new() -> Self {
41        Fuse(CachePadded::new(AtomicBool::new(false)))
42    }
43
44    /// Reads the current state of this fuse.
45    fn load(&self) -> FuseState {
46        use std::sync::atomic::Ordering;
47
48        match self.0.load(Ordering::Relaxed) {
49            false => FuseState::Unset,
50            true => FuseState::Set,
51        }
52    }
53
54    /// Sets this fuse to the [`Set`](FuseState::Set) state.
55    fn set(&self) {
56        use std::sync::atomic::Ordering;
57
58        self.0.store(true, Ordering::Relaxed)
59    }
60}
61
62// ExactSizeAccumulator implementations.
63
64pub struct IterReducer<Reduce> {
65    pub(super) reduce: Reduce,
66}
67
68impl<Output, Reduce> ExactSizeAccumulator<Output, Option<Output>> for IterReducer<Reduce>
69where
70    Reduce: Fn(Output, Output) -> Output,
71{
72    #[inline(always)]
73    fn accumulate_exact(&self, iter: impl ExactSizeIterator<Item = Output>) -> Option<Output> {
74        iter.reduce(&self.reduce)
75    }
76}
77
78pub struct IterFolder<Init, Fold> {
79    pub(super) init: Init,
80    pub(super) fold: Fold,
81}
82
83impl<Item, Output, Init, Fold> ExactSizeAccumulator<Item, Output> for IterFolder<Init, Fold>
84where
85    Init: Fn(usize) -> Output,
86    Fold: Fn(Output, Item) -> Output,
87{
88    #[inline(always)]
89    fn accumulate_exact(&self, iter: impl ExactSizeIterator<Item = Item>) -> Output {
90        let init = (self.init)(iter.len());
91        iter.fold(init, &self.fold)
92    }
93}
94
95pub struct TryIterFolder<Init, TryFold> {
96    pub(super) init: Init,
97    pub(super) try_fold: TryFold,
98}
99
100#[cfg(not(feature = "nightly"))]
101impl<Item, Output, E, Init, TryFold> ExactSizeAccumulator<Item, Result<Output, E>>
102    for TryIterFolder<Init, TryFold>
103where
104    Init: Fn(usize) -> Output,
105    TryFold: Fn(Output, Item) -> Result<Output, E>,
106{
107    #[inline(always)]
108    fn accumulate_exact(&self, mut iter: impl ExactSizeIterator<Item = Item>) -> Result<Output, E> {
109        let init = (self.init)(iter.len());
110        iter.try_fold(init, &self.try_fold)
111    }
112}
113
114#[cfg(feature = "nightly")]
115impl<Item, Output, R, Init, TryFold> ExactSizeAccumulator<Item, R> for TryIterFolder<Init, TryFold>
116where
117    Init: Fn(usize) -> Output,
118    TryFold: Fn(Output, Item) -> R,
119    R: Try<Output = Output>,
120{
121    #[inline(always)]
122    fn accumulate_exact(&self, mut iter: impl ExactSizeIterator<Item = Item>) -> R {
123        let init = (self.init)(iter.len());
124        iter.try_fold(init, &self.try_fold)
125    }
126}
127
128// Accumulator implementations.
129
130pub struct IterAccumulator<Init, ProcessItem, Finalize> {
131    pub(super) init: Init,
132    pub(super) process_item: ProcessItem,
133    pub(super) finalize: Finalize,
134}
135
136impl<Item, Accum, Output, Init, ProcessItem, Finalize> Accumulator<Item, Output>
137    for IterAccumulator<Init, ProcessItem, Finalize>
138where
139    Init: Fn() -> Accum,
140    ProcessItem: Fn(Accum, Item) -> Accum,
141    Finalize: Fn(Accum) -> Output,
142{
143    #[inline(always)]
144    fn accumulate(&self, iter: impl Iterator<Item = Item>) -> Output {
145        let mut accumulator = (self.init)();
146        for item in iter {
147            accumulator = (self.process_item)(accumulator, item);
148        }
149        (self.finalize)(accumulator)
150    }
151}
152
153pub struct ShortCircuitingAccumulator<Init, ProcessItem, Finalize> {
154    pub(super) fuse: Fuse,
155    pub(super) init: Init,
156    pub(super) process_item: ProcessItem,
157    pub(super) finalize: Finalize,
158}
159
160#[cfg(not(feature = "nightly"))]
161impl<Item, Accum, Break, Output, Init, ProcessItem, Finalize> Accumulator<Item, Output>
162    for ShortCircuitingAccumulator<Init, ProcessItem, Finalize>
163where
164    Init: Fn() -> Accum,
165    ProcessItem: Fn(Accum, Item) -> ControlFlow<Break, Accum>,
166    Finalize: Fn(ControlFlow<Break, Accum>) -> Output,
167{
168    #[inline(always)]
169    fn accumulate(&self, mut iter: impl Iterator<Item = Item>) -> Output {
170        let mut accumulator = (self.init)();
171        let result = 'outer: {
172            while let FuseState::Unset = self.fuse.load() {
173                let Some(item) = iter.next() else {
174                    break;
175                };
176
177                match (self.process_item)(accumulator, item) {
178                    ControlFlow::Continue(acc) => {
179                        accumulator = acc;
180                        continue;
181                    }
182                    control_flow @ ControlFlow::Break(_) => {
183                        self.fuse.set();
184                        break 'outer control_flow;
185                    }
186                }
187            }
188            ControlFlow::Continue(accumulator)
189        };
190        (self.finalize)(result)
191    }
192}
193
194#[cfg(feature = "nightly")]
195impl<Item, Accum, R, Output, Init, ProcessItem, Finalize> Accumulator<Item, Output>
196    for ShortCircuitingAccumulator<Init, ProcessItem, Finalize>
197where
198    Init: Fn() -> Accum,
199    ProcessItem: Fn(Accum, Item) -> R,
200    Finalize: Fn(R) -> Output,
201    R: Try<Output = Accum>,
202{
203    #[inline(always)]
204    fn accumulate(&self, mut iter: impl Iterator<Item = Item>) -> Output {
205        let mut accumulator = (self.init)();
206        let result = 'outer: {
207            while let FuseState::Unset = self.fuse.load() {
208                let Some(item) = iter.next() else {
209                    break;
210                };
211
212                match (self.process_item)(accumulator, item).branch() {
213                    ControlFlow::Continue(acc) => {
214                        accumulator = acc;
215                        continue;
216                    }
217                    ControlFlow::Break(residual) => {
218                        self.fuse.set();
219                        break 'outer R::from_residual(residual);
220                    }
221                }
222            }
223            R::from_output(accumulator)
224        };
225        (self.finalize)(result)
226    }
227}
228
229pub struct AdaptorAccumulator<Inner, TransformItem> {
230    pub(super) inner: Inner,
231    pub(super) transform_item: TransformItem,
232}
233
234impl<InnerItem, Item, Output, Inner, TransformItem> Accumulator<InnerItem, Output>
235    for AdaptorAccumulator<Inner, TransformItem>
236where
237    Inner: Accumulator<Item, Output>,
238    TransformItem: Fn(InnerItem) -> Option<Item>,
239{
240    #[inline(always)]
241    fn accumulate(&self, iter: impl Iterator<Item = InnerItem>) -> Output {
242        self.inner.accumulate(iter.filter_map(&self.transform_item))
243    }
244}
245
246// Collect adaptor implementations.
247
248pub struct IterCollector<T> {
249    pub(super) _phantom: PhantomData<fn() -> T>,
250}
251
252impl<Item, T> Accumulator<Item, T> for IterCollector<T>
253where
254    T: FromIterator<Item>,
255{
256    #[inline(always)]
257    fn accumulate(&self, iter: impl Iterator<Item = Item>) -> T {
258        T::from_iter(iter)
259    }
260}
261
262pub struct TryIterCollector<T> {
263    pub(super) fuse: Fuse,
264    pub(super) _phantom: PhantomData<fn() -> T>,
265}
266
267#[cfg(not(feature = "nightly"))]
268impl<Item, C, E> Accumulator<Result<Item, E>, Result<C, E>> for TryIterCollector<C>
269where
270    C: FromIterator<Item>,
271{
272    #[inline(always)]
273    fn accumulate(&self, iter: impl Iterator<Item = Result<Item, E>>) -> Result<C, E> {
274        let mut error = None;
275        let c = C::from_iter(iter.map_while(|item| match item {
276            Err(e) => {
277                self.fuse.set();
278                error = Some(e);
279                None
280            }
281            Ok(x) => match self.fuse.load() {
282                FuseState::Set => None,
283                FuseState::Unset => Some(x),
284            },
285        }));
286        match error {
287            None => Ok(c),
288            Some(e) => Err(e),
289        }
290    }
291}
292
293#[cfg(feature = "nightly")]
294impl<Item, C> Accumulator<Item, <Item::Residual as Residual<C>>::TryType> for TryIterCollector<C>
295where
296    Item: Try,
297    Item::Residual: Residual<C>,
298    C: FromIterator<Item::Output>,
299{
300    #[inline(always)]
301    fn accumulate(
302        &self,
303        iter: impl Iterator<Item = Item>,
304    ) -> <Item::Residual as Residual<C>>::TryType {
305        let mut residual = None;
306        let c = C::from_iter(iter.map_while(|item| match item.branch() {
307            ControlFlow::Break(e) => {
308                self.fuse.set();
309                residual = Some(e);
310                None
311            }
312            ControlFlow::Continue(x) => match self.fuse.load() {
313                FuseState::Set => None,
314                FuseState::Unset => Some(x),
315            },
316        }));
317        match residual {
318            None => Try::from_output(c),
319            Some(e) => FromResidual::from_residual(e),
320        }
321    }
322}
323
324// Product/Sum adaptor implementations on top of the (ExactSize)Accumulator
325// traits.
326
327pub struct SumAccumulator;
328
329impl<Item, Output> Accumulator<Item, Output> for SumAccumulator
330where
331    Output: Sum<Item>,
332{
333    #[inline(always)]
334    fn accumulate(&self, iter: impl Iterator<Item = Item>) -> Output {
335        iter.sum()
336    }
337}
338
339impl<Item, Output> ExactSizeAccumulator<Item, Output> for SumAccumulator
340where
341    Output: Sum<Item>,
342{
343    #[inline(always)]
344    fn accumulate_exact(&self, iter: impl ExactSizeIterator<Item = Item>) -> Output {
345        iter.sum()
346    }
347}
348
349pub struct ProductAccumulator;
350
351impl<Item, Output> Accumulator<Item, Output> for ProductAccumulator
352where
353    Output: Product<Item>,
354{
355    #[inline(always)]
356    fn accumulate(&self, iter: impl Iterator<Item = Item>) -> Output {
357        iter.product()
358    }
359}
360
361impl<Item, Output> ExactSizeAccumulator<Item, Output> for ProductAccumulator
362where
363    Output: Product<Item>,
364{
365    #[inline(always)]
366    fn accumulate_exact(&self, iter: impl ExactSizeIterator<Item = Item>) -> Output {
367        iter.product()
368    }
369}
370
371/// The result of the [`minmax()`](super::ParallelIteratorExt::minmax) and
372/// related iterator adaptors.
373#[derive(Clone, Copy, Debug, PartialEq, Eq)]
374pub enum MinMaxResult<T> {
375    /// The iterator was empty.
376    NoElements,
377    /// The iterator only had one item.
378    OneElement(T),
379    /// The iterator had at least two items.
380    MinMax {
381        /// The minimal item.
382        min: T,
383        /// The maximal item.
384        max: T,
385    },
386}
387
388impl<T> MinMaxResult<T> {
389    pub(super) fn map<U, F>(self, f: F) -> MinMaxResult<U>
390    where
391        F: Fn(T) -> U,
392    {
393        match self {
394            MinMaxResult::NoElements => MinMaxResult::NoElements,
395            MinMaxResult::OneElement(x) => MinMaxResult::OneElement(f(x)),
396            MinMaxResult::MinMax { min, max } => MinMaxResult::MinMax {
397                min: f(min),
398                max: f(max),
399            },
400        }
401    }
402
403    /// Returns a reference to the minimal element, if this result isn't empty.
404    ///
405    /// ```
406    /// # use paralight::iter::MinMaxResult;
407    /// assert_eq!(MinMaxResult::<i32>::NoElements.min(), None);
408    /// assert_eq!(MinMaxResult::OneElement(42).min(), Some(&42));
409    /// assert_eq!(MinMaxResult::MinMax { min: 42, max: 123 }.min(), Some(&42));
410    /// ```
411    pub fn min(&self) -> Option<&T> {
412        match self {
413            MinMaxResult::NoElements => None,
414            MinMaxResult::OneElement(x) => Some(x),
415            MinMaxResult::MinMax { min, max: _ } => Some(min),
416        }
417    }
418
419    /// Returns the minimal element, if this result isn't empty.
420    ///
421    /// ```
422    /// # use paralight::iter::MinMaxResult;
423    /// assert_eq!(MinMaxResult::<i32>::NoElements.into_min(), None);
424    /// assert_eq!(MinMaxResult::OneElement(42).into_min(), Some(42));
425    /// assert_eq!(
426    ///     MinMaxResult::MinMax { min: 42, max: 123 }.into_min(),
427    ///     Some(42)
428    /// );
429    /// ```
430    pub fn into_min(self) -> Option<T> {
431        match self {
432            MinMaxResult::NoElements => None,
433            MinMaxResult::OneElement(x) => Some(x),
434            MinMaxResult::MinMax { min, max: _ } => Some(min),
435        }
436    }
437
438    /// Returns a reference to the maximal element, if this result isn't empty.
439    ///
440    /// ```
441    /// # use paralight::iter::MinMaxResult;
442    /// assert_eq!(MinMaxResult::<i32>::NoElements.max(), None);
443    /// assert_eq!(MinMaxResult::OneElement(42).max(), Some(&42));
444    /// assert_eq!(MinMaxResult::MinMax { min: 42, max: 123 }.max(), Some(&123));
445    /// ```
446    pub fn max(&self) -> Option<&T> {
447        match self {
448            MinMaxResult::NoElements => None,
449            MinMaxResult::OneElement(x) => Some(x),
450            MinMaxResult::MinMax { min: _, max } => Some(max),
451        }
452    }
453
454    /// Returns the maximal element, if this result isn't empty.
455    ///
456    /// ```
457    /// # use paralight::iter::MinMaxResult;
458    /// assert_eq!(MinMaxResult::<i32>::NoElements.into_max(), None);
459    /// assert_eq!(MinMaxResult::OneElement(42).into_max(), Some(42));
460    /// assert_eq!(
461    ///     MinMaxResult::MinMax { min: 42, max: 123 }.into_max(),
462    ///     Some(123)
463    /// );
464    /// ```
465    pub fn into_max(self) -> Option<T> {
466        match self {
467            MinMaxResult::NoElements => None,
468            MinMaxResult::OneElement(x) => Some(x),
469            MinMaxResult::MinMax { min: _, max } => Some(max),
470        }
471    }
472
473    /// Returns references to the minimal-maximal elements, if this result isn't
474    /// empty.
475    ///
476    /// ```
477    /// # use paralight::iter::MinMaxResult;
478    /// assert_eq!(MinMaxResult::<i32>::NoElements.as_option(), None);
479    /// assert_eq!(MinMaxResult::OneElement(42).as_option(), Some((&42, &42)));
480    /// assert_eq!(
481    ///     MinMaxResult::MinMax { min: 42, max: 123 }.as_option(),
482    ///     Some((&42, &123))
483    /// );
484    /// ```
485    pub fn as_option(&self) -> Option<(&T, &T)>
486    where
487        T: Clone,
488    {
489        match self {
490            MinMaxResult::NoElements => None,
491            MinMaxResult::OneElement(x) => Some((x, x)),
492            MinMaxResult::MinMax { min, max } => Some((min, max)),
493        }
494    }
495
496    /// Returns the minimal-maximal pair, if this result isn't empty.
497    ///
498    /// ```
499    /// # use paralight::iter::MinMaxResult;
500    /// assert_eq!(MinMaxResult::<i32>::NoElements.into_option(), None);
501    /// assert_eq!(MinMaxResult::OneElement(42).into_option(), Some((42, 42)));
502    /// assert_eq!(
503    ///     MinMaxResult::MinMax { min: 42, max: 123 }.into_option(),
504    ///     Some((42, 123))
505    /// );
506    /// ```
507    pub fn into_option(self) -> Option<(T, T)>
508    where
509        T: Clone,
510    {
511        match self {
512            MinMaxResult::NoElements => None,
513            MinMaxResult::OneElement(x) => Some((x.clone(), x)),
514            MinMaxResult::MinMax { min, max } => Some((min, max)),
515        }
516    }
517}
518
519pub struct MinMaxAccumulator<F> {
520    pub(super) f: F,
521}
522
523impl<Item, F> Accumulator<Item, MinMaxResult<Item>> for &MinMaxAccumulator<F>
524where
525    F: Fn(&Item, &Item) -> Ordering,
526{
527    #[inline(always)]
528    fn accumulate(&self, mut iter: impl Iterator<Item = Item>) -> MinMaxResult<Item> {
529        let (mut min, mut max) = match iter.next() {
530            None => return MinMaxResult::NoElements,
531            Some(x) => match iter.next() {
532                None => return MinMaxResult::OneElement(x),
533                Some(y) => match (self.f)(&x, &y) {
534                    Ordering::Less | Ordering::Equal => (x, y),
535                    Ordering::Greater => (y, x),
536                },
537            },
538        };
539
540        loop {
541            let a = match iter.next() {
542                Some(a) => a,
543                None => break,
544            };
545            let b = match iter.next() {
546                Some(b) => b,
547                None => {
548                    if let Ordering::Less = (self.f)(&a, &min) {
549                        min = a;
550                    } else if let Ordering::Greater | Ordering::Equal = (self.f)(&a, &max) {
551                        max = a;
552                    }
553                    break;
554                }
555            };
556
557            match (self.f)(&a, &b) {
558                Ordering::Less | Ordering::Equal => {
559                    if let Ordering::Less = (self.f)(&a, &min) {
560                        min = a;
561                    }
562                    if let Ordering::Greater | Ordering::Equal = (self.f)(&b, &max) {
563                        max = b;
564                    }
565                }
566                Ordering::Greater => {
567                    if let Ordering::Less = (self.f)(&b, &min) {
568                        min = b;
569                    }
570                    if let Ordering::Greater | Ordering::Equal = (self.f)(&a, &max) {
571                        max = a;
572                    }
573                }
574            }
575        }
576
577        MinMaxResult::MinMax { min, max }
578    }
579}
580
581impl<Item, F> ExactSizeAccumulator<MinMaxResult<Item>, MinMaxResult<Item>> for &MinMaxAccumulator<F>
582where
583    F: Fn(&Item, &Item) -> Ordering,
584{
585    #[inline(always)]
586    fn accumulate_exact(
587        &self,
588        iter: impl ExactSizeIterator<Item = MinMaxResult<Item>>,
589    ) -> MinMaxResult<Item> {
590        iter.fold(MinMaxResult::NoElements, |x, y| match (x, y) {
591            (MinMaxResult::NoElements, z) | (z, MinMaxResult::NoElements) => z,
592            (MinMaxResult::OneElement(a), MinMaxResult::OneElement(b)) => match (self.f)(&a, &b) {
593                Ordering::Less | Ordering::Equal => MinMaxResult::MinMax { min: a, max: b },
594                Ordering::Greater => MinMaxResult::MinMax { min: b, max: a },
595            },
596            (MinMaxResult::OneElement(z), MinMaxResult::MinMax { min, max }) => {
597                if let Ordering::Less | Ordering::Equal = (self.f)(&z, &min) {
598                    MinMaxResult::MinMax { min: z, max }
599                } else if let Ordering::Greater = (self.f)(&z, &max) {
600                    MinMaxResult::MinMax { min, max: z }
601                } else {
602                    MinMaxResult::MinMax { min, max }
603                }
604            }
605            (MinMaxResult::MinMax { min, max }, MinMaxResult::OneElement(z)) => {
606                if let Ordering::Less = (self.f)(&z, &min) {
607                    MinMaxResult::MinMax { min: z, max }
608                } else if let Ordering::Greater | Ordering::Equal = (self.f)(&z, &max) {
609                    MinMaxResult::MinMax { min, max: z }
610                } else {
611                    MinMaxResult::MinMax { min, max }
612                }
613            }
614            (
615                MinMaxResult::MinMax {
616                    min: min1,
617                    max: max1,
618                },
619                MinMaxResult::MinMax {
620                    min: min2,
621                    max: max2,
622                },
623            ) => {
624                let min = match (self.f)(&min1, &min2) {
625                    Ordering::Less | Ordering::Equal => min1,
626                    Ordering::Greater => min2,
627                };
628                let max = match (self.f)(&max1, &max2) {
629                    Ordering::Greater => max1,
630                    Ordering::Less | Ordering::Equal => max2,
631                };
632                MinMaxResult::MinMax { min, max }
633            }
634        })
635    }
636}
637
638// Adaptor implementations.
639
640/// This struct is created by the [`map()`](super::ParallelIteratorExt::map)
641/// method on [`ParallelIteratorExt`](super::ParallelIteratorExt).
642///
643/// You most likely won't need to interact with this struct directly, as it
644/// implements the [`ParallelIterator`] and
645/// [`ParallelIteratorExt`](super::ParallelIteratorExt) traits, but it is
646/// nonetheless public because of the `must_use` annotation.
647#[must_use = "iterator adaptors are lazy"]
648pub struct Map<Inner: ParallelIterator, F> {
649    pub(super) inner: Inner,
650    pub(super) f: F,
651}
652
653impl<Inner: ParallelIterator, T, F> ParallelAdaptor for Map<Inner, F>
654where
655    F: Fn(Inner::Item) -> T + Sync,
656{
657    type Item = T;
658    type Inner = Inner;
659
660    fn descriptor(
661        self,
662    ) -> ParallelAdaptorDescriptor<
663        Self::Item,
664        Self::Inner,
665        impl Fn(<Self::Inner as ParallelIterator>::Item) -> Option<Self::Item> + Sync,
666    > {
667        ParallelAdaptorDescriptor {
668            inner: self.inner,
669            transform_item: move |item| Some((self.f)(item)),
670        }
671    }
672}
673
674// Iterator implementations
675
676/// This struct is created by the
677/// [`panic_fuse()`](super::ParallelIteratorExt::panic_fuse) method on
678/// [`ParallelIteratorExt`](super::ParallelIteratorExt).
679///
680/// You most likely won't need to interact with this struct directly, as it
681/// implements the [`ParallelIterator`] and
682/// [`ParallelIteratorExt`](super::ParallelIteratorExt) traits, but it is
683/// nonetheless public because of the `must_use` annotation.
684#[must_use = "iterator adaptors are lazy"]
685pub struct PanicFuse<Inner: ParallelIterator> {
686    pub(super) inner: Inner,
687}
688
689impl<Inner: ParallelIterator> ParallelIterator for PanicFuse<Inner> {
690    type Item = Inner::Item;
691
692    fn upper_bounded_pipeline<Output: Send, Accum>(
693        self,
694        init: impl Fn() -> Accum + Sync,
695        process_item: impl Fn(Accum, usize, Self::Item) -> ControlFlow<Accum, Accum> + Sync,
696        finalize: impl Fn(Accum) -> Output + Sync,
697        reduce: impl Fn(Output, Output) -> Output,
698    ) -> Output {
699        let fuse = Fuse::new();
700        self.inner.upper_bounded_pipeline(
701            || (init(), scopeguard::guard(&fuse, |fuse| fuse.set())),
702            |(acc, guard), index, item| match guard.load() {
703                FuseState::Unset => match process_item(acc, index, item) {
704                    ControlFlow::Continue(acc) => ControlFlow::Continue((acc, guard)),
705                    ControlFlow::Break(acc) => ControlFlow::Break((acc, guard)),
706                },
707                FuseState::Set => ControlFlow::Break((acc, guard)),
708            },
709            |(acc, guard)| {
710                ScopeGuard::into_inner(guard);
711                finalize(acc)
712            },
713            reduce,
714        )
715    }
716
717    fn iter_pipeline<Output, Accum: Send>(
718        self,
719        accum: impl Accumulator<Self::Item, Accum> + Sync,
720        reduce: impl ExactSizeAccumulator<Accum, Output>,
721    ) -> Output {
722        let accumulator = PanicFuseAccumulator {
723            inner: accum,
724            fuse: Fuse::new(),
725        };
726        self.inner.iter_pipeline(accumulator, reduce)
727    }
728}
729
730struct PanicFuseAccumulator<Inner> {
731    inner: Inner,
732    fuse: Fuse,
733}
734
735impl<Item, Output, Inner> Accumulator<Item, Output> for PanicFuseAccumulator<Inner>
736where
737    Inner: Accumulator<Item, Output>,
738{
739    #[inline(always)]
740    fn accumulate(&self, iter: impl Iterator<Item = Item>) -> Output {
741        let guard = scopeguard::guard(&self.fuse, |fuse| fuse.set());
742        let output = self
743            .inner
744            .accumulate(iter.take_while(|_| self.fuse.load() == FuseState::Unset));
745        ScopeGuard::into_inner(guard);
746        output
747    }
748}
749
750#[cfg(test)]
751mod test {
752    use super::*;
753
754    #[test]
755    fn minmaxresult_min() {
756        assert_eq!(MinMaxResult::<i32>::NoElements.min(), None);
757        assert_eq!(MinMaxResult::OneElement(42).min(), Some(&42));
758        assert_eq!(MinMaxResult::MinMax { min: 42, max: 123 }.min(), Some(&42));
759    }
760
761    #[test]
762    fn minmaxresult_into_min() {
763        assert_eq!(MinMaxResult::<i32>::NoElements.into_min(), None);
764        assert_eq!(MinMaxResult::OneElement(42).into_min(), Some(42));
765        assert_eq!(
766            MinMaxResult::MinMax { min: 42, max: 123 }.into_min(),
767            Some(42)
768        );
769    }
770
771    #[test]
772    fn minmaxresult_max() {
773        assert_eq!(MinMaxResult::<i32>::NoElements.max(), None);
774        assert_eq!(MinMaxResult::OneElement(42).max(), Some(&42));
775        assert_eq!(MinMaxResult::MinMax { min: 42, max: 123 }.max(), Some(&123));
776    }
777
778    #[test]
779    fn minmaxresult_into_max() {
780        assert_eq!(MinMaxResult::<i32>::NoElements.into_max(), None);
781        assert_eq!(MinMaxResult::OneElement(42).into_max(), Some(42));
782        assert_eq!(
783            MinMaxResult::MinMax { min: 42, max: 123 }.into_max(),
784            Some(123)
785        );
786    }
787
788    #[test]
789    fn minmaxresult_as_option() {
790        assert_eq!(MinMaxResult::<i32>::NoElements.as_option(), None);
791        assert_eq!(MinMaxResult::OneElement(42).as_option(), Some((&42, &42)));
792        assert_eq!(
793            MinMaxResult::MinMax { min: 42, max: 123 }.as_option(),
794            Some((&42, &123))
795        );
796    }
797
798    #[test]
799    fn minmaxresult_into_option() {
800        assert_eq!(MinMaxResult::<i32>::NoElements.into_option(), None);
801        assert_eq!(MinMaxResult::OneElement(42).into_option(), Some((42, 42)));
802        assert_eq!(
803            MinMaxResult::MinMax { min: 42, max: 123 }.into_option(),
804            Some((42, 123))
805        );
806    }
807
808    #[test]
809    fn minmax_accumulator_edge_cases() {
810        let accumulator = &MinMaxAccumulator {
811            f: |x: &(i32, i32), y: &(i32, i32)| x.0.cmp(&y.0),
812        };
813
814        // OneElement + OneElement
815        assert_eq!(
816            accumulator.accumulate_exact(
817                [
818                    MinMaxResult::OneElement((0, 0)),
819                    MinMaxResult::OneElement((0, 1))
820                ]
821                .into_iter()
822            ),
823            MinMaxResult::MinMax {
824                min: (0, 0),
825                max: (0, 1),
826            }
827        );
828        assert_eq!(
829            accumulator.accumulate_exact(
830                [
831                    MinMaxResult::OneElement((1, 0)),
832                    MinMaxResult::OneElement((0, 1))
833                ]
834                .into_iter()
835            ),
836            MinMaxResult::MinMax {
837                min: (0, 1),
838                max: (1, 0),
839            }
840        );
841
842        // OneElement + MinMax
843        assert_eq!(
844            accumulator.accumulate_exact(
845                [
846                    MinMaxResult::OneElement((0, 0)),
847                    MinMaxResult::MinMax {
848                        min: (0, 1),
849                        max: (0, 2),
850                    }
851                ]
852                .into_iter()
853            ),
854            MinMaxResult::MinMax {
855                min: (0, 0),
856                max: (0, 2),
857            }
858        );
859        assert_eq!(
860            accumulator.accumulate_exact(
861                [
862                    MinMaxResult::OneElement((1, 0)),
863                    MinMaxResult::MinMax {
864                        min: (0, 1),
865                        max: (2, 2),
866                    }
867                ]
868                .into_iter()
869            ),
870            MinMaxResult::MinMax {
871                min: (0, 1),
872                max: (2, 2),
873            }
874        );
875        assert_eq!(
876            accumulator.accumulate_exact(
877                [
878                    MinMaxResult::OneElement((0, 0)),
879                    MinMaxResult::MinMax {
880                        min: (1, 1),
881                        max: (2, 2),
882                    }
883                ]
884                .into_iter()
885            ),
886            MinMaxResult::MinMax {
887                min: (0, 0),
888                max: (2, 2),
889            }
890        );
891        assert_eq!(
892            accumulator.accumulate_exact(
893                [
894                    MinMaxResult::OneElement((2, 0)),
895                    MinMaxResult::MinMax {
896                        min: (0, 1),
897                        max: (1, 2),
898                    }
899                ]
900                .into_iter()
901            ),
902            MinMaxResult::MinMax {
903                min: (0, 1),
904                max: (2, 0),
905            }
906        );
907
908        // MinMax + OneElement
909        assert_eq!(
910            accumulator.accumulate_exact(
911                [
912                    MinMaxResult::MinMax {
913                        min: (0, 0),
914                        max: (0, 1),
915                    },
916                    MinMaxResult::OneElement((0, 2)),
917                ]
918                .into_iter()
919            ),
920            MinMaxResult::MinMax {
921                min: (0, 0),
922                max: (0, 2),
923            }
924        );
925        assert_eq!(
926            accumulator.accumulate_exact(
927                [
928                    MinMaxResult::MinMax {
929                        min: (0, 0),
930                        max: (2, 1),
931                    },
932                    MinMaxResult::OneElement((1, 2)),
933                ]
934                .into_iter()
935            ),
936            MinMaxResult::MinMax {
937                min: (0, 0),
938                max: (2, 1),
939            }
940        );
941        assert_eq!(
942            accumulator.accumulate_exact(
943                [
944                    MinMaxResult::MinMax {
945                        min: (1, 0),
946                        max: (2, 1),
947                    },
948                    MinMaxResult::OneElement((0, 2)),
949                ]
950                .into_iter()
951            ),
952            MinMaxResult::MinMax {
953                min: (0, 2),
954                max: (2, 1),
955            }
956        );
957        assert_eq!(
958            accumulator.accumulate_exact(
959                [
960                    MinMaxResult::MinMax {
961                        min: (0, 0),
962                        max: (1, 1),
963                    },
964                    MinMaxResult::OneElement((2, 2)),
965                ]
966                .into_iter()
967            ),
968            MinMaxResult::MinMax {
969                min: (0, 0),
970                max: (2, 2),
971            }
972        );
973    }
974}