Skip to main content

lender/fallible_adapters/
convert.rs

1use core::{marker::PhantomData, ops::ControlFlow};
2
3use stable_try_trait_v2::Try;
4
5use crate::{
6    DoubleEndedFallibleLender, DoubleEndedLender, ExactSizeFallibleLender, ExactSizeLender,
7    FallibleLend, FallibleLender, FallibleLending, FusedFallibleLender, FusedLender, ImplBound,
8    Lender, Lending, Ref,
9};
10
11trait LendingResult<'lend, E, __ImplBound: ImplBound = Ref<'lend, Self>>:
12    Lending<'lend, __ImplBound, Lend = Result<Self::Item, E>>
13{
14    type Item: 'lend;
15}
16
17impl<'a, Bound, T, E, I> LendingResult<'a, E, Bound> for I
18where
19    Bound: ImplBound,
20    T: 'a,
21    I: Lending<'a, Bound, Lend = Result<T, E>>,
22{
23    type Item = T;
24}
25
26trait LenderResult<E>: Lender + for<'all> LendingResult<'all, E> {}
27
28impl<E, I> LenderResult<E> for I where I: Lender + for<'all> LendingResult<'all, E> {}
29
30/// A fallible lending iterator that wraps a normal lending
31/// iterator over [`Result`]s.
32///
33/// This struct is created by [`Lender::convert`].
34#[derive(Clone, Debug)]
35#[repr(transparent)]
36#[must_use = "lenders are lazy and do nothing unless consumed"]
37pub struct Convert<E, I> {
38    iter: I,
39    _marker: PhantomData<fn() -> E>,
40}
41
42impl<E, I: crate::Lender> Convert<E, I> {
43    #[inline(always)]
44    pub(crate) fn new(iter: I) -> Self {
45        let _ = <I as crate::Lender>::__check_covariance(crate::CovariantProof::new());
46        Self {
47            iter,
48            _marker: PhantomData,
49        }
50    }
51
52    /// Returns the inner lender.
53    #[inline(always)]
54    pub fn into_inner(self) -> I {
55        self.iter
56    }
57}
58
59impl<'lend, E, I> FallibleLending<'lend> for Convert<E, I>
60where
61    I: LendingResult<'lend, E>,
62{
63    type Lend = <<I as Lending<'lend>>::Lend as Try>::Output;
64}
65
66impl<E, I> FallibleLender for Convert<E, I>
67where
68    I: LenderResult<E>,
69{
70    type Error = E;
71    // SAFETY: the lend is that of I
72    crate::unsafe_assume_covariance_fallible!();
73
74    #[inline]
75    fn next(&mut self) -> Result<Option<FallibleLend<'_, Self>>, E> {
76        match self.iter.next() {
77            Some(Ok(i)) => Ok(Some(i)),
78            Some(Err(e)) => Err(e),
79            None => Ok(None),
80        }
81    }
82
83    #[inline(always)]
84    fn size_hint(&self) -> (usize, Option<usize>) {
85        self.iter.size_hint()
86    }
87
88    #[inline]
89    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> Result<R, Self::Error>
90    where
91        Self: Sized,
92        F: FnMut(B, FallibleLend<'_, Self>) -> Result<R, Self::Error>,
93        R: Try<Output = B>,
94    {
95        match self.iter.try_fold(init, |acc, item| match item {
96            Ok(v) => super::try_fold_with(f(acc, v)),
97            Err(e) => ControlFlow::Break(Err(e)),
98        }) {
99            ControlFlow::Continue(acc) => Ok(R::from_output(acc)),
100            ControlFlow::Break(r) => r,
101        }
102    }
103
104    #[inline]
105    fn fold<B, F>(mut self, init: B, mut f: F) -> Result<B, Self::Error>
106    where
107        Self: Sized,
108        F: FnMut(B, FallibleLend<'_, Self>) -> Result<B, Self::Error>,
109    {
110        // Delegate to the inner lender's try_fold using
111        // ControlFlow to propagate item errors.
112        match self.iter.try_fold(init, |acc, item| match item {
113            Ok(v) => match f(acc, v) {
114                Ok(b) => ControlFlow::Continue(b),
115                Err(e) => ControlFlow::Break(e),
116            },
117            Err(e) => ControlFlow::Break(e),
118        }) {
119            ControlFlow::Continue(acc) => Ok(acc),
120            ControlFlow::Break(e) => Err(e),
121        }
122    }
123}
124
125impl<E, I> DoubleEndedFallibleLender for Convert<E, I>
126where
127    I: DoubleEndedLender + LenderResult<E>,
128{
129    #[inline]
130    fn next_back(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
131        match self.iter.next_back() {
132            Some(Ok(i)) => Ok(Some(i)),
133            Some(Err(e)) => Err(e),
134            None => Ok(None),
135        }
136    }
137
138    #[inline]
139    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> Result<R, Self::Error>
140    where
141        Self: Sized,
142        F: FnMut(B, FallibleLend<'_, Self>) -> Result<R, Self::Error>,
143        R: Try<Output = B>,
144    {
145        match self.iter.try_rfold(init, |acc, item| match item {
146            Ok(v) => super::try_fold_with(f(acc, v)),
147            Err(e) => ControlFlow::Break(Err(e)),
148        }) {
149            ControlFlow::Continue(acc) => Ok(R::from_output(acc)),
150            ControlFlow::Break(r) => r,
151        }
152    }
153
154    #[inline]
155    fn rfold<B, F>(mut self, init: B, mut f: F) -> Result<B, Self::Error>
156    where
157        Self: Sized,
158        F: FnMut(B, FallibleLend<'_, Self>) -> Result<B, Self::Error>,
159    {
160        match self.iter.try_rfold(init, |acc, item| match item {
161            Ok(v) => match f(acc, v) {
162                Ok(b) => ControlFlow::Continue(b),
163                Err(e) => ControlFlow::Break(e),
164            },
165            Err(e) => ControlFlow::Break(e),
166        }) {
167            ControlFlow::Continue(acc) => Ok(acc),
168            ControlFlow::Break(e) => Err(e),
169        }
170    }
171}
172
173impl<E, I> ExactSizeFallibleLender for Convert<E, I>
174where
175    I: ExactSizeLender + LenderResult<E>,
176{
177    #[inline(always)]
178    fn len(&self) -> usize {
179        self.iter.len()
180    }
181
182    #[inline(always)]
183    fn is_empty(&self) -> bool {
184        self.iter.is_empty()
185    }
186}
187
188impl<E, I> FusedFallibleLender for Convert<E, I> where I: FusedLender + LenderResult<E> {}