1use aliasable::boxed::AliasableBox;
2use core::fmt;
3use maybe_dangling::MaybeDangling;
4
5use crate::{Covar, FusedLender, IntoLender, Lend, Lender, Lending, Map, try_trait_v2::Try};
6
7#[must_use = "lenders are lazy and do nothing unless consumed"]
12pub struct Flatten<'this, L: Lender>
13where
14 for<'all> Lend<'all, L>: IntoLender,
15{
16 inner: FlattenCompat<'this, L>,
17}
18
19impl<L: Lender> Flatten<'_, L>
20where
21 for<'all> Lend<'all, L>: IntoLender,
22{
23 #[inline]
24 pub(crate) fn new(lender: L) -> Self {
25 let _ = L::__check_covariance(crate::CovariantProof::new());
26 Self {
27 inner: FlattenCompat::new(lender),
28 }
29 }
30
31 #[inline(always)]
33 pub fn into_inner(self) -> L {
34 *AliasableBox::into_unique(self.inner.lender)
35 }
36}
37
38impl<L: Lender + fmt::Debug> fmt::Debug for Flatten<'_, L>
43where
44 for<'all> Lend<'all, L>: IntoLender,
45 for<'all> <Lend<'all, L> as IntoLender>::Lender: fmt::Debug,
46{
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.debug_struct("Flatten")
49 .field("inner", &self.inner)
50 .finish()
51 }
52}
53
54impl<'lend, 'this, L: Lender> Lending<'lend> for Flatten<'this, L>
55where
56 for<'all> Lend<'all, L>: IntoLender,
57{
58 type Lend = Lend<'lend, <Lend<'this, L> as IntoLender>::Lender>;
59}
60
61impl<L: Lender> Lender for Flatten<'_, L>
62where
63 for<'all> Lend<'all, L>: IntoLender,
64{
65 crate::unsafe_assume_covariance!();
67 #[inline(always)]
68 fn next(&mut self) -> Option<Lend<'_, Self>> {
69 self.inner.next()
70 }
71
72 #[inline(always)]
73 fn size_hint(&self) -> (usize, Option<usize>) {
74 self.inner.size_hint()
75 }
76
77 #[inline(always)]
78 fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
79 where
80 Self: Sized,
81 F: FnMut(B, Lend<'_, Self>) -> R,
82 R: Try<Output = B>,
83 {
84 self.inner.try_fold(init, f)
85 }
86
87 #[inline(always)]
88 fn fold<B, F>(self, init: B, f: F) -> B
89 where
90 Self: Sized,
91 F: FnMut(B, Lend<'_, Self>) -> B,
92 {
93 self.inner.fold(init, f)
94 }
95
96 #[inline(always)]
97 fn count(self) -> usize
98 where
99 Self: Sized,
100 {
101 self.inner.count()
102 }
103}
104
105impl<L: FusedLender> FusedLender for Flatten<'_, L> where for<'all> Lend<'all, L>: IntoLender {}
106
107#[must_use = "lenders are lazy and do nothing unless consumed"]
113pub struct FlatMap<'this, L: Lender, F>
114where
115 Map<L, F>: Lender,
116 for<'all> Lend<'all, Map<L, F>>: IntoLender,
117{
118 inner: FlattenCompat<'this, Map<L, F>>,
119}
120
121impl<L: Lender, F> FlatMap<'_, L, F>
122where
123 Map<L, F>: Lender,
124 for<'all> Lend<'all, Map<L, F>>: IntoLender,
125{
126 #[inline]
127 pub(crate) fn new(lender: L, f: Covar<F>) -> Self {
128 let _ = L::__check_covariance(crate::CovariantProof::new());
129 Self {
130 inner: FlattenCompat::new(Map::new(lender, f)),
131 }
132 }
133
134 #[inline(always)]
136 pub fn into_inner(self) -> L {
137 (*AliasableBox::into_unique(self.inner.lender)).into_inner()
138 }
139
140 #[inline(always)]
142 pub fn into_parts(self) -> (L, Covar<F>) {
143 (*AliasableBox::into_unique(self.inner.lender)).into_parts()
144 }
145}
146
147impl<L: Lender + fmt::Debug, F> fmt::Debug for FlatMap<'_, L, F>
152where
153 Map<L, F>: Lender,
154 for<'all> Lend<'all, Map<L, F>>: IntoLender,
155 for<'all> <Lend<'all, Map<L, F>> as IntoLender>::Lender: fmt::Debug,
156{
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 f.debug_struct("FlatMap")
159 .field("inner", &self.inner)
160 .finish()
161 }
162}
163
164impl<'lend, 'this, L: Lender, F> Lending<'lend> for FlatMap<'this, L, F>
165where
166 Map<L, F>: Lender,
167 for<'all> Lend<'all, Map<L, F>>: IntoLender,
168{
169 type Lend = Lend<'lend, <Lend<'this, Map<L, F>> as IntoLender>::Lender>;
170}
171
172impl<L: Lender, F> Lender for FlatMap<'_, L, F>
173where
174 Map<L, F>: Lender,
175 for<'all> Lend<'all, Map<L, F>>: IntoLender,
176{
177 crate::unsafe_assume_covariance!();
179 #[inline(always)]
180 fn next(&mut self) -> Option<Lend<'_, Self>> {
181 self.inner.next()
182 }
183
184 #[inline(always)]
185 fn size_hint(&self) -> (usize, Option<usize>) {
186 self.inner.size_hint()
187 }
188
189 #[inline(always)]
190 fn try_fold<B, G, R>(&mut self, init: B, f: G) -> R
191 where
192 Self: Sized,
193 G: FnMut(B, Lend<'_, Self>) -> R,
194 R: Try<Output = B>,
195 {
196 self.inner.try_fold(init, f)
197 }
198
199 #[inline(always)]
200 fn fold<B, G>(self, init: B, f: G) -> B
201 where
202 Self: Sized,
203 G: FnMut(B, Lend<'_, Self>) -> B,
204 {
205 self.inner.fold(init, f)
206 }
207
208 #[inline(always)]
209 fn count(self) -> usize
210 where
211 Self: Sized,
212 {
213 self.inner.count()
214 }
215}
216
217impl<L: FusedLender, F> FusedLender for FlatMap<'_, L, F>
218where
219 Map<L, F>: Lender,
220 for<'all> Lend<'all, Map<L, F>>: IntoLender,
221{
222}
223
224pub(crate) struct FlattenCompat<'this, L: Lender>
225where
226 for<'all> Lend<'all, L>: IntoLender,
227{
228 inner: MaybeDangling<Option<<Lend<'this, L> as IntoLender>::Lender>>,
235 lender: AliasableBox<L>,
236}
237
238impl<L: Lender> FlattenCompat<'_, L>
239where
240 for<'all> Lend<'all, L>: IntoLender,
241{
242 #[inline]
243 pub(crate) fn new(lender: L) -> Self {
244 let _ = L::__check_covariance(crate::CovariantProof::new());
245 Self {
246 inner: MaybeDangling::new(None),
247 lender: AliasableBox::from_unique(alloc::boxed::Box::new(lender)),
248 }
249 }
250}
251
252impl<L: Lender + fmt::Debug> fmt::Debug for FlattenCompat<'_, L>
257where
258 for<'all> Lend<'all, L>: IntoLender,
259 for<'all> <Lend<'all, L> as IntoLender>::Lender: fmt::Debug,
260{
261 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262 f.debug_struct("FlattenCompat")
263 .field("lender", &self.lender)
264 .field("inner", &self.inner)
265 .finish()
266 }
267}
268
269impl<'lend, 'this, L: Lender> Lending<'lend> for FlattenCompat<'this, L>
270where
271 for<'all> Lend<'all, L>: IntoLender,
272{
273 type Lend = Lend<'lend, <Lend<'this, L> as IntoLender>::Lender>;
274}
275
276impl<'this, L: Lender> Lender for FlattenCompat<'this, L>
277where
278 for<'all> Lend<'all, L>: IntoLender,
279{
280 crate::unsafe_assume_covariance!();
282 #[inline]
283 #[allow(clippy::question_mark)]
284 fn next(&mut self) -> Option<Lend<'_, Self>> {
285 loop {
286 #[allow(clippy::deref_addrof)]
288 let reborrow = unsafe { &mut *(&raw mut *self.inner) };
289 if let Some(inner) = reborrow {
290 if let Some(x) = inner.next() {
291 return Some(x);
292 }
293 }
294
295 *self.inner = self.lender.next().map(|l| unsafe {
298 core::mem::transmute::<
299 <Lend<'_, L> as IntoLender>::Lender,
300 <Lend<'this, L> as IntoLender>::Lender,
301 >(l.into_lender())
302 });
303
304 if self.inner.is_none() {
305 return None;
306 }
307 }
308 }
309
310 #[inline]
311 fn size_hint(&self) -> (usize, Option<usize>) {
312 let inner_len = match &*self.inner {
313 Some(inner) => inner.size_hint().0,
314 None => 0,
315 };
316 (inner_len, None)
317 }
318
319 #[inline]
320 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
321 where
322 Self: Sized,
323 F: FnMut(B, Lend<'_, Self>) -> R,
324 R: Try<Output = B>,
325 {
326 use core::ops::ControlFlow;
327 let mut acc = init;
328 if let Some(ref mut inner) = *self.inner {
329 match inner.try_fold(acc, &mut f).branch() {
330 ControlFlow::Continue(b) => acc = b,
331 ControlFlow::Break(r) => return R::from_residual(r),
332 }
333 }
334 *self.inner = None;
335 loop {
336 let Some(l) = self.lender.next() else { break };
337 *self.inner = Some(unsafe {
340 core::mem::transmute::<
341 <Lend<'_, L> as IntoLender>::Lender,
342 <Lend<'this, L> as IntoLender>::Lender,
343 >(l.into_lender())
344 });
345 if let Some(ref mut inner) = *self.inner {
346 match inner.try_fold(acc, &mut f).branch() {
347 ControlFlow::Continue(b) => acc = b,
348 ControlFlow::Break(r) => return R::from_residual(r),
349 }
350 }
351 *self.inner = None;
352 }
353 R::from_output(acc)
354 }
355
356 #[inline]
357 fn fold<B, F>(mut self, init: B, mut f: F) -> B
358 where
359 Self: Sized,
360 F: FnMut(B, Lend<'_, Self>) -> B,
361 {
362 let mut acc = init;
363 if let Some(inner) = self.inner.take() {
364 acc = inner.fold(acc, &mut f);
365 }
366 while let Some(l) = self.lender.next() {
367 let sub = unsafe {
370 core::mem::transmute::<
371 <Lend<'_, L> as IntoLender>::Lender,
372 <Lend<'this, L> as IntoLender>::Lender,
373 >(l.into_lender())
374 };
375 acc = sub.fold(acc, &mut f);
376 }
377 acc
378 }
379
380 #[inline]
381 fn count(self) -> usize
382 where
383 Self: Sized,
384 {
385 self.fold(0, |count, _| count + 1)
386 }
387}
388
389impl<L: FusedLender> FusedLender for FlattenCompat<'_, L> where for<'all> Lend<'all, L>: IntoLender {}
390
391#[cfg(test)]
392mod test {
393 use super::*;
394
395 struct Parent([i32; 4]);
396
397 impl<'lend> Lending<'lend> for Parent {
398 type Lend = Child<'lend>;
399 }
400
401 impl Lender for Parent {
402 crate::check_covariance!();
403 fn next(&mut self) -> Option<Lend<'_, Self>> {
404 Some(Child { array_ref: &self.0 })
405 }
406 }
407
408 struct Child<'a> {
409 array_ref: &'a [i32; 4],
410 }
411
412 impl<'a, 'lend> Lending<'lend> for Child<'a> {
413 type Lend = &'lend [i32; 4];
414 }
415
416 impl<'a> Lender for Child<'a> {
417 crate::check_covariance!();
418 fn next(&mut self) -> Option<Lend<'_, Self>> {
419 Some(self.array_ref)
420 }
421 }
422
423 #[test]
428 fn test_flatten() {
429 let lender = Parent([0, 1, 2, 3]);
430 let mut flatten = lender.flatten();
431 flatten.next();
432 moved_flatten(flatten);
433 }
434
435 fn moved_flatten(mut flatten: Flatten<Parent>) {
436 let next_array_ref = flatten.next().unwrap() as *const _;
437 let array_ref = &flatten.inner.lender.0 as *const _;
438 assert_eq!(
439 next_array_ref, array_ref,
440 "Array references returned by the flattened lender should refer to the array in the parent lender"
441 );
442 }
443
444 #[test]
445 fn test_flatmap_empty() {
446 use crate::traits::IteratorExt;
447
448 let mut l = [1, 0, 2]
449 .into_iter()
450 .into_lender()
451 .flat_map(unsafe { crate::Covar::__new(|n: i32| (0..n).into_lender()) });
453 assert_eq!(l.next(), Some(0));
454 assert_eq!(l.next(), Some(0));
455 assert_eq!(l.next(), Some(1));
456 assert_eq!(l.next(), None);
457 assert_eq!(l.next(), None);
458 }
459}