Skip to main content

lender/traits/
double_ended.rs

1use core::{num::NonZeroUsize, ops::ControlFlow};
2
3use crate::{
4    try_trait_v2::{FromResidual, Try, internal::NeverShortCircuit},
5    *,
6};
7
8/// The [`Lender`] version of [`core::iter::DoubleEndedIterator`].
9pub trait DoubleEndedLender: Lender {
10    /// Removes and returns a lend from the end of the lender.
11    ///
12    /// Returns `None` when there are no more elements.
13    ///
14    /// See [`DoubleEndedIterator::next_back`].
15    fn next_back(&mut self) -> Option<Lend<'_, Self>>;
16
17    /// Advances the lender from the back by `n` elements.
18    ///
19    /// See
20    /// [`DoubleEndedIterator::advance_back_by`].
21    #[inline]
22    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
23        for i in 0..n {
24            if self.next_back().is_none() {
25                // SAFETY: `i` is always less than `n`.
26                return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
27            }
28        }
29        Ok(())
30    }
31
32    /// Returns the `n`th element from the end of the lender.
33    ///
34    /// See [`DoubleEndedIterator::nth_back`].
35    #[inline]
36    fn nth_back(&mut self, n: usize) -> Option<Lend<'_, Self>> {
37        self.advance_back_by(n).ok()?;
38        self.next_back()
39    }
40
41    /// The reverse version of [`Lender::try_fold`]: it takes elements starting from
42    /// the back of the lender.
43    ///
44    /// See
45    /// [`DoubleEndedIterator::try_rfold`].
46    #[inline]
47    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
48    where
49        F: FnMut(B, Lend<'_, Self>) -> R,
50        R: Try<Output = B>,
51    {
52        let mut accum = init;
53        while let Some(x) = self.next_back() {
54            accum = match f(accum, x).branch() {
55                ControlFlow::Break(x) => return FromResidual::from_residual(x),
56                ControlFlow::Continue(x) => x,
57            };
58        }
59        Try::from_output(accum)
60    }
61
62    /// The reverse version of [`Lender::fold`]: it takes elements starting from
63    /// the back of the lender.
64    ///
65    /// See [`DoubleEndedIterator::rfold`].
66    #[inline]
67    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
68    where
69        Self: Sized,
70        F: FnMut(B, Lend<'_, Self>) -> B,
71    {
72        self.try_rfold(init, |acc, x| NeverShortCircuit(f(acc, x)))
73            .0
74    }
75
76    /// The reverse version of [`Lender::find`]: it searches for an element of the
77    /// lender from the back that satisfies the predicate.
78    ///
79    /// See [`DoubleEndedIterator::rfind`].
80    #[inline]
81    fn rfind<P>(&mut self, mut predicate: P) -> Option<Lend<'_, Self>>
82    where
83        Self: Sized,
84        P: FnMut(&Lend<'_, Self>) -> bool,
85    {
86        while let Some(x) = self.next_back() {
87            if predicate(&x) {
88                // SAFETY: polonius return
89                return Some(unsafe { core::mem::transmute::<Lend<'_, Self>, Lend<'_, Self>>(x) });
90            }
91        }
92        None
93    }
94}
95
96impl<L: DoubleEndedLender> DoubleEndedLender for &mut L {
97    #[inline(always)]
98    fn next_back(&mut self) -> Option<Lend<'_, Self>> {
99        (**self).next_back()
100    }
101
102    #[inline(always)]
103    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
104        (**self).advance_back_by(n)
105    }
106
107    #[inline(always)]
108    fn nth_back(&mut self, n: usize) -> Option<Lend<'_, Self>> {
109        (**self).nth_back(n)
110    }
111}
112
113/// The [`FallibleLender`] version of [`core::iter::DoubleEndedIterator`].
114pub trait DoubleEndedFallibleLender: FallibleLender {
115    /// Removes and returns a lend from the end of the lender, or an error.
116    ///
117    /// Returns `Ok(None)` when there are no more elements.
118    ///
119    /// See [`DoubleEndedLender::next_back`].
120    fn next_back(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error>;
121
122    /// Advances the lender from the back by `n` elements.
123    ///
124    /// See [`DoubleEndedLender::advance_back_by`].
125    #[inline]
126    fn advance_back_by(&mut self, n: usize) -> Result<Result<(), NonZeroUsize>, Self::Error> {
127        for i in 0..n {
128            if self.next_back()?.is_none() {
129                // SAFETY: `i` is always less than `n`.
130                return Ok(Err(unsafe { NonZeroUsize::new_unchecked(n - i) }));
131            }
132        }
133        Ok(Ok(()))
134    }
135
136    /// Returns the `n`th element from the end of the lender.
137    ///
138    /// See [`DoubleEndedLender::nth_back`].
139    #[inline]
140    fn nth_back(&mut self, n: usize) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
141        if self.advance_back_by(n)?.is_err() {
142            return Ok(None);
143        }
144        self.next_back()
145    }
146
147    /// The reverse version of [`FallibleLender::try_fold`]: it takes elements
148    /// starting from the back of the lender.
149    ///
150    /// See [`DoubleEndedLender::try_rfold`].
151    #[inline]
152    fn try_rfold<B, F, R>(&mut self, mut init: B, mut f: F) -> Result<R, Self::Error>
153    where
154        F: FnMut(B, FallibleLend<'_, Self>) -> Result<R, Self::Error>,
155        R: Try<Output = B>,
156    {
157        while let Some(v) = self.next_back()? {
158            match f(init, v)?.branch() {
159                ControlFlow::Break(residual) => return Ok(R::from_residual(residual)),
160                ControlFlow::Continue(output) => init = output,
161            }
162        }
163        Ok(R::from_output(init))
164    }
165
166    /// The reverse version of [`FallibleLender::fold`]: it takes elements
167    /// starting from the back of the lender.
168    ///
169    /// See [`DoubleEndedLender::rfold`].
170    #[inline]
171    fn rfold<B, F>(mut self, init: B, mut f: F) -> Result<B, Self::Error>
172    where
173        Self: Sized,
174        F: FnMut(B, FallibleLend<'_, Self>) -> Result<B, Self::Error>,
175    {
176        self.try_rfold(init, |acc, item| f(acc, item).map(NeverShortCircuit))
177            .map(|res| res.0)
178    }
179
180    /// The reverse version of [`FallibleLender::find`]: it searches for an element
181    /// from the back that satisfies the predicate.
182    ///
183    /// See [`DoubleEndedLender::rfind`].
184    #[inline]
185    fn rfind<P>(&mut self, mut predicate: P) -> Result<Option<FallibleLend<'_, Self>>, Self::Error>
186    where
187        Self: Sized,
188        P: FnMut(&FallibleLend<'_, Self>) -> Result<bool, Self::Error>,
189    {
190        while let Some(x) = self.next_back()? {
191            if predicate(&x)? {
192                // SAFETY: polonius return
193                return Ok(Some(unsafe {
194                    core::mem::transmute::<FallibleLend<'_, Self>, FallibleLend<'_, Self>>(x)
195                }));
196            }
197        }
198        Ok(None)
199    }
200}
201
202impl<L: DoubleEndedFallibleLender> DoubleEndedFallibleLender for &mut L {
203    #[inline(always)]
204    fn next_back(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
205        (**self).next_back()
206    }
207
208    #[inline(always)]
209    fn advance_back_by(&mut self, n: usize) -> Result<Result<(), NonZeroUsize>, Self::Error> {
210        (**self).advance_back_by(n)
211    }
212
213    #[inline(always)]
214    fn nth_back(&mut self, n: usize) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
215        (**self).nth_back(n)
216    }
217}