Skip to main content

lender/fallible_adapters/
flatten.rs

1use aliasable::boxed::AliasableBox;
2use core::fmt;
3use maybe_dangling::MaybeDangling;
4
5use crate::{
6    Covar, FallibleLend, FallibleLender, FallibleLending, FusedFallibleLender, IntoFallibleLender,
7    Map, try_trait_v2::Try,
8};
9
10/// A fallible lender that flattens one level of nesting in a lender of lenders.
11///
12/// This `struct` is created by the
13/// [`flatten()`](crate::FallibleLender::flatten) method on
14/// [`FallibleLender`]. See its documentation for more.
15#[must_use = "lenders are lazy and do nothing unless consumed"]
16pub struct Flatten<'this, L: FallibleLender>
17where
18    for<'all> FallibleLend<'all, L>: IntoFallibleLender,
19{
20    inner: FlattenCompat<'this, L>,
21}
22
23impl<L: FallibleLender> Flatten<'_, L>
24where
25    for<'all> FallibleLend<'all, L>: IntoFallibleLender,
26{
27    #[inline]
28    pub(crate) fn new(lender: L) -> Self {
29        Self {
30            inner: FlattenCompat::new(lender),
31        }
32    }
33
34    /// Returns the inner lender.
35    #[inline(always)]
36    pub fn into_inner(self) -> L {
37        *AliasableBox::into_unique(self.inner.lender)
38    }
39}
40
41// Clone is not implemented for Flatten because the inner sub-lender may
42// reference the AliasableBox allocation; a clone would create a new allocation
43// but the cloned inner sub-lender would still reference the original.
44
45impl<L: FallibleLender + fmt::Debug> fmt::Debug for Flatten<'_, L>
46where
47    for<'all> FallibleLend<'all, L>: IntoFallibleLender,
48    for<'all> <FallibleLend<'all, L> as IntoFallibleLender>::FallibleLender: fmt::Debug,
49{
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        f.debug_struct("Flatten")
52            .field("inner", &self.inner)
53            .finish()
54    }
55}
56
57impl<'lend, 'this, L: FallibleLender> FallibleLending<'lend> for Flatten<'this, L>
58where
59    for<'all> FallibleLend<'all, L>: IntoFallibleLender,
60{
61    type Lend = FallibleLend<'lend, <FallibleLend<'this, L> as IntoFallibleLender>::FallibleLender>;
62}
63
64impl<L: FallibleLender> FallibleLender for Flatten<'_, L>
65where
66    for<'all> FallibleLend<'all, L>: IntoFallibleLender<Error = L::Error>,
67{
68    type Error = L::Error;
69    // SAFETY: the lend is that of the inner lender
70    crate::unsafe_assume_covariance_fallible!();
71
72    #[inline(always)]
73    fn next(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
74        self.inner.next()
75    }
76
77    #[inline(always)]
78    fn size_hint(&self) -> (usize, Option<usize>) {
79        self.inner.size_hint()
80    }
81
82    #[inline(always)]
83    fn try_fold<B, F, R>(&mut self, init: B, f: F) -> Result<R, Self::Error>
84    where
85        Self: Sized,
86        F: FnMut(B, FallibleLend<'_, Self>) -> Result<R, Self::Error>,
87        R: Try<Output = B>,
88    {
89        self.inner.try_fold(init, f)
90    }
91
92    #[inline(always)]
93    fn fold<B, F>(self, init: B, f: F) -> Result<B, Self::Error>
94    where
95        Self: Sized,
96        F: FnMut(B, FallibleLend<'_, Self>) -> Result<B, Self::Error>,
97    {
98        self.inner.fold(init, f)
99    }
100
101    #[inline(always)]
102    fn count(self) -> Result<usize, Self::Error>
103    where
104        Self: Sized,
105    {
106        self.inner.count()
107    }
108}
109
110impl<L: FusedFallibleLender> FusedFallibleLender for Flatten<'_, L> where
111    for<'all> FallibleLend<'all, L>: IntoFallibleLender<Error = L::Error>
112{
113}
114
115/// A fallible lender that maps each element to a lender, and yields
116/// the elements of the produced lenders.
117///
118/// This `struct` is created by the
119/// [`flat_map()`](crate::FallibleLender::flat_map) method on
120/// [`FallibleLender`]. See its documentation for more.
121#[must_use = "lenders are lazy and do nothing unless consumed"]
122pub struct FlatMap<'this, L: FallibleLender, F>
123where
124    Map<L, F>: FallibleLender,
125    for<'all> FallibleLend<'all, Map<L, F>>: IntoFallibleLender,
126{
127    inner: FlattenCompat<'this, Map<L, F>>,
128}
129
130impl<L: FallibleLender, F> FlatMap<'_, L, F>
131where
132    Map<L, F>: FallibleLender,
133    for<'all> FallibleLend<'all, Map<L, F>>: IntoFallibleLender,
134{
135    #[inline]
136    pub(crate) fn new(lender: L, f: Covar<F>) -> Self {
137        Self {
138            inner: FlattenCompat::new(Map::new_fallible(lender, f)),
139        }
140    }
141
142    /// Returns the inner lender.
143    #[inline(always)]
144    pub fn into_inner(self) -> L {
145        (*AliasableBox::into_unique(self.inner.lender)).into_inner()
146    }
147
148    /// Returns the inner lender and the mapping function.
149    #[inline(always)]
150    pub fn into_parts(self) -> (L, Covar<F>) {
151        (*AliasableBox::into_unique(self.inner.lender)).into_parts()
152    }
153}
154
155// Clone is not implemented for FlatMap because the inner sub-lender may
156// reference the AliasableBox allocation; a clone would create a new allocation
157// but the cloned inner sub-lender would still reference the original.
158
159impl<L: FallibleLender + fmt::Debug, F> fmt::Debug for FlatMap<'_, L, F>
160where
161    Map<L, F>: FallibleLender,
162    for<'all> FallibleLend<'all, Map<L, F>>: IntoFallibleLender,
163    for<'all> <FallibleLend<'all, Map<L, F>> as IntoFallibleLender>::FallibleLender: fmt::Debug,
164{
165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        f.debug_struct("FlatMap")
167            .field("inner", &self.inner)
168            .finish()
169    }
170}
171
172impl<'lend, 'this, L: FallibleLender, F> FallibleLending<'lend> for FlatMap<'this, L, F>
173where
174    Map<L, F>: FallibleLender,
175    for<'all> FallibleLend<'all, Map<L, F>>: IntoFallibleLender,
176{
177    type Lend =
178        FallibleLend<'lend, <FallibleLend<'this, Map<L, F>> as IntoFallibleLender>::FallibleLender>;
179}
180
181impl<L: FallibleLender, F> FallibleLender for FlatMap<'_, L, F>
182where
183    Map<L, F>: FallibleLender<Error = L::Error>,
184    for<'all> FallibleLend<'all, Map<L, F>>: IntoFallibleLender<Error = L::Error>,
185{
186    type Error = L::Error;
187    // SAFETY: the lend is that of the inner lender
188    crate::unsafe_assume_covariance_fallible!();
189
190    #[inline(always)]
191    fn next(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
192        self.inner.next()
193    }
194
195    #[inline(always)]
196    fn size_hint(&self) -> (usize, Option<usize>) {
197        self.inner.size_hint()
198    }
199
200    #[inline(always)]
201    fn try_fold<B, G, R>(&mut self, init: B, f: G) -> Result<R, Self::Error>
202    where
203        Self: Sized,
204        G: FnMut(B, FallibleLend<'_, Self>) -> Result<R, Self::Error>,
205        R: Try<Output = B>,
206    {
207        self.inner.try_fold(init, f)
208    }
209
210    #[inline(always)]
211    fn fold<B, G>(self, init: B, f: G) -> Result<B, Self::Error>
212    where
213        Self: Sized,
214        G: FnMut(B, FallibleLend<'_, Self>) -> Result<B, Self::Error>,
215    {
216        self.inner.fold(init, f)
217    }
218
219    #[inline(always)]
220    fn count(self) -> Result<usize, Self::Error>
221    where
222        Self: Sized,
223    {
224        self.inner.count()
225    }
226}
227
228impl<L: FusedFallibleLender, F> FusedFallibleLender for FlatMap<'_, L, F>
229where
230    Map<L, F>: FallibleLender<Error = L::Error>,
231    for<'all> FallibleLend<'all, Map<L, F>>: IntoFallibleLender<Error = L::Error>,
232{
233}
234
235/// The internal implementation backing both [`Flatten`] and
236/// [`FlatMap`] for fallible lenders.
237pub(crate) struct FlattenCompat<'this, L: FallibleLender>
238where
239    for<'all> FallibleLend<'all, L>: IntoFallibleLender,
240{
241    // MaybeDangling wraps the inner lender to indicate it may reference data
242    // from the outer lender. AliasableBox eliminates noalias retagging that would
243    // invalidate the inner reference when the struct is moved.
244    // Field order ensures outer lender drops last.
245    //
246    // See https://github.com/WanderLanz/Lender/issues/34
247    inner: MaybeDangling<Option<<FallibleLend<'this, L> as IntoFallibleLender>::FallibleLender>>,
248    lender: AliasableBox<L>,
249}
250
251impl<L: FallibleLender> FlattenCompat<'_, L>
252where
253    for<'all> FallibleLend<'all, L>: IntoFallibleLender,
254{
255    #[inline]
256    pub(crate) fn new(lender: L) -> Self {
257        let _ = L::__check_covariance(crate::CovariantProof::new());
258        Self {
259            inner: MaybeDangling::new(None),
260            lender: AliasableBox::from_unique(alloc::boxed::Box::new(lender)),
261        }
262    }
263}
264
265// Clone is not implemented for FlattenCompat because the inner sub-lender may
266// reference the AliasableBox allocation; a clone would create a new allocation
267// but the cloned inner sub-lender would still reference the original.
268
269impl<L: FallibleLender + fmt::Debug> fmt::Debug for FlattenCompat<'_, L>
270where
271    for<'all> FallibleLend<'all, L>: IntoFallibleLender,
272    for<'all> <FallibleLend<'all, L> as IntoFallibleLender>::FallibleLender: fmt::Debug,
273{
274    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275        f.debug_struct("FlattenCompat")
276            .field("lender", &self.lender)
277            .field("inner", &self.inner)
278            .finish()
279    }
280}
281
282impl<'lend, 'this, L: FallibleLender> FallibleLending<'lend> for FlattenCompat<'this, L>
283where
284    for<'all> FallibleLend<'all, L>: IntoFallibleLender,
285{
286    type Lend = FallibleLend<'lend, <FallibleLend<'this, L> as IntoFallibleLender>::FallibleLender>;
287}
288
289impl<'this, L: FallibleLender> FallibleLender for FlattenCompat<'this, L>
290where
291    for<'all> FallibleLend<'all, L>: IntoFallibleLender<Error = L::Error>,
292{
293    type Error = L::Error;
294    // SAFETY: the lend is that of the inner lender
295    crate::unsafe_assume_covariance_fallible!();
296
297    #[inline]
298    fn next(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
299        loop {
300            // SAFETY: Polonius return
301            #[allow(clippy::deref_addrof)]
302            let reborrow = unsafe { &mut *(&raw mut *self.inner) };
303            if let Some(inner) = reborrow {
304                if let Some(x) = inner.next()? {
305                    return Ok(Some(x));
306                }
307            }
308            // SAFETY: inner is manually guaranteed to be
309            // the only FallibleLend alive of the inner
310            // lender
311            *self.inner = self.lender.next()?.map(|l| unsafe {
312                core::mem::transmute::<
313                    <FallibleLend<'_, L> as IntoFallibleLender>::FallibleLender,
314                    <FallibleLend<'this, L> as IntoFallibleLender>::FallibleLender,
315                >(l.into_fallible_lender())
316            });
317
318            if self.inner.is_none() {
319                return Ok(None);
320            }
321        }
322    }
323
324    #[inline]
325    fn size_hint(&self) -> (usize, Option<usize>) {
326        (
327            match &*self.inner {
328                Some(inner) => inner.size_hint().0,
329                None => 0,
330            },
331            None,
332        )
333    }
334
335    #[inline]
336    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> Result<R, Self::Error>
337    where
338        Self: Sized,
339        F: FnMut(B, FallibleLend<'_, Self>) -> Result<R, Self::Error>,
340        R: Try<Output = B>,
341    {
342        use core::ops::ControlFlow;
343        let mut acc = init;
344        if let Some(ref mut inner) = *self.inner {
345            match inner.try_fold(acc, &mut f)?.branch() {
346                ControlFlow::Continue(b) => acc = b,
347                ControlFlow::Break(r) => return Ok(R::from_residual(r)),
348            }
349        }
350        *self.inner = None;
351        loop {
352            let Some(l) = self.lender.next()? else { break };
353            // SAFETY: inner is manually guaranteed to be the only
354            // lend alive of the inner lender
355            *self.inner = Some(unsafe {
356                core::mem::transmute::<
357                    <FallibleLend<'_, L> as IntoFallibleLender>::FallibleLender,
358                    <FallibleLend<'this, L> as IntoFallibleLender>::FallibleLender,
359                >(l.into_fallible_lender())
360            });
361            if let Some(ref mut inner) = *self.inner {
362                match inner.try_fold(acc, &mut f)?.branch() {
363                    ControlFlow::Continue(b) => acc = b,
364                    ControlFlow::Break(r) => return Ok(R::from_residual(r)),
365                }
366            }
367            *self.inner = None;
368        }
369        Ok(R::from_output(acc))
370    }
371
372    #[inline]
373    fn fold<B, F>(mut self, init: B, mut f: F) -> Result<B, Self::Error>
374    where
375        Self: Sized,
376        F: FnMut(B, FallibleLend<'_, Self>) -> Result<B, Self::Error>,
377    {
378        let mut acc = init;
379        if let Some(inner) = self.inner.take() {
380            acc = inner.fold(acc, &mut f)?;
381        }
382        while let Some(l) = self.lender.next()? {
383            // SAFETY: inner is manually guaranteed to be the only
384            // lend alive of the inner lender
385            let sub = unsafe {
386                core::mem::transmute::<
387                    <FallibleLend<'_, L> as IntoFallibleLender>::FallibleLender,
388                    <FallibleLend<'this, L> as IntoFallibleLender>::FallibleLender,
389                >(l.into_fallible_lender())
390            };
391            acc = sub.fold(acc, &mut f)?;
392        }
393        Ok(acc)
394    }
395
396    #[inline]
397    fn count(self) -> Result<usize, Self::Error>
398    where
399        Self: Sized,
400    {
401        self.fold(0, |count, _| Ok(count + 1))
402    }
403}
404
405impl<L: FusedFallibleLender> FusedFallibleLender for FlattenCompat<'_, L> where
406    for<'all> FallibleLend<'all, L>: IntoFallibleLender<Error = L::Error>
407{
408}
409
410#[cfg(test)]
411mod test {
412    use core::convert::Infallible;
413
414    use super::*;
415    use crate::{IntoFallible, Lend, Lender, Lending};
416
417    struct Parent([i32; 4]);
418
419    impl<'lend> Lending<'lend> for Parent {
420        type Lend = Child<'lend>;
421    }
422
423    impl Lender for Parent {
424        crate::check_covariance!();
425        fn next(&mut self) -> Option<Lend<'_, Self>> {
426            Some(Child { array_ref: &self.0 })
427        }
428    }
429
430    struct Child<'a> {
431        array_ref: &'a [i32; 4],
432    }
433
434    impl<'a, 'lend> FallibleLending<'lend> for Child<'a> {
435        type Lend = &'lend [i32; 4];
436    }
437
438    impl<'a> FallibleLender for Child<'a> {
439        type Error = Infallible;
440        crate::check_covariance_fallible!();
441
442        fn next(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
443            Ok(Some(self.array_ref))
444        }
445    }
446
447    // This test will fail if FlattenCompat stores L instead of Box<L>. In that
448    // case, when Flatten<Parent> is moved, the array inside Parent is moved,
449    // too, but FlattenCompat.inner will still contain a Child holding a
450    // reference to the previous location.
451    #[test]
452    fn test_flatten() -> Result<(), Infallible> {
453        let lender = Parent([0, 1, 2, 3]);
454        let mut flatten = lender.into_fallible().flatten();
455        let _ = flatten.next();
456        moved_flatten(flatten)
457    }
458
459    fn moved_flatten(mut flatten: Flatten<IntoFallible<Parent>>) -> Result<(), Infallible> {
460        let next_array_ref = flatten.next()?.unwrap() as *const _;
461        let array_ref = &flatten.inner.lender.lender.0 as *const _;
462        assert_eq!(
463            next_array_ref, array_ref,
464            "Array references returned by the flattened FallibleLender should refer to the array in the parent FallibleLender"
465        );
466        Ok(())
467    }
468
469    #[test]
470    fn test_flat_map_empty() {
471        use crate::traits::IteratorExt;
472
473        let mut l = [1, 0, 2]
474            .into_iter()
475            .into_lender()
476            .into_fallible()
477            // SAFETY: closure returns an owned Result (trivially covariant).
478            .flat_map(unsafe {
479                crate::Covar::__new(|n: i32| Ok((0..n).into_lender().into_fallible()))
480            });
481        assert_eq!(l.next(), Ok(Some(0)));
482        assert_eq!(l.next(), Ok(Some(0)));
483        assert_eq!(l.next(), Ok(Some(1)));
484        assert_eq!(l.next(), Ok(None));
485        assert_eq!(l.next(), Ok(None));
486    }
487}