lending_iterator/lending_iterator/_mod.rs
1//! Trait and helper adapter definitions.
2
3use {
4 ::core::{
5 marker::PhantomData,
6 ops::Not,
7 },
8 ::never_say_never::{
9 Never as ǃ,
10 },
11 ::nougat::{
12 *,
13 },
14 crate::{
15 higher_kinded_types::{*, Apply as A, HKTItem},
16 },
17 self::{
18 adapters::*,
19 }
20};
21
22pub use self::{
23 r#dyn::LendingIteratorDyn,
24};
25
26#[path = "adapters/_mod.rs"]
27pub
28mod adapters;
29
30/// Functions, extension traits and types allowing direct construction of
31/// [`LendingIterator`]s (no need for custom types or implementations!).
32#[path = "constructors/_mod.rs"]
33pub
34mod constructors;
35
36use r#dyn::*;
37#[path = "dyn/_mod.rs"]
38pub(in crate)
39mod r#dyn;
40
41mod impls;
42
43macro_rules! with_cfg_better_docs {( $($rules:tt)* ) => (
44 macro_rules! __emit__ { $($rules)* }
45
46 #[cfg(feature = "better-docs")]
47 __emit__! {
48 true
49 }
50
51 #[cfg(not(feature = "better-docs"))]
52 __emit__! {
53 false
54 }
55)}
56with_cfg_better_docs! {(
57 $(true $($if_better_docs:tt)?)?
58 $(false $($if_not_better_docs:tt)?)?
59) => (
60
61
62$($($if_better_docs)?
63 /// ⚠️ **NEVER NAME THIS TRAIT DIRECTLY** ⚠️
64 /// Implementation detail of `#[gat] trait LendingIterator`.
65 ///
66 /// - ⚠️ **The exact name of this trait may change within semver-compatible
67 /// releases** ⚠️
68 ///
69 /// The only reason this trait is even exposed to begin with is because of
70 /// the `notable_trait` feature greatly improving the readability of
71 /// [`LendingIterator`]'s adapters.
72 #[doc(notable_trait)]
73 pub trait LendingIteratorඞItem<'next, Bounds = &'next Self> {
74 /// The "output" of this whole hand-rolled GAT:
75 /// think of `LendingIteratorඞItem<'lt>::T` as of `LendingIterator::Item<'lt>`.
76 ///
77 /// ⚠️ **NEVER NAME THIS TRAIT OR ASSOC TYPE DIRECTLY** ⚠️ yadda yadda.
78 type T;
79 }
80)?
81
82#[allow(type_alias_bounds)]
83/// `generic_associated_types`-agnostic shorthand for
84/// <code>\<I as [LendingIterator]\>::Item\<\'lt\></code>
85pub
86type Item<'lt, I : LendingIterator> =
87 Gat!(<I as LendingIterator>::Item<'lt>)
88;
89
90/// The meat of the crate. Trait similar to [`Iterator`] but **for the return
91/// type of the `fn next(&'_ mut self)` method being allowed to depend on that
92/// `'_`**.
93///
94/// <details open class="custom"><summary><span class="summary-box"><span>Click to hide</span></span></summary>
95///
96/// - That type is called the `Item<'_>` type, and is a
97/// [`generic_associated_type`](#a-generic-associated-type).
98///
99/// - That difference is crucial both in terms of signature complexity
100/// (as this crate's API ought to prove 😅) and borrowing semantics.
101///
102/// Mainly, when yielded, such `Item<'_>` is still `&mut` borrowing `*self`, so
103/// **it won't be possible to further advance the iterator** (or anything else,
104/// for that matter), **until the current item is no longer used.**
105///
106/// That is: **the `Item<'_>`s yielded by a [`LendingIterator`] cannot
107/// coëxist!**
108///
109/// - this will thus impose serious usability limitations on it (_e.g_, no
110/// `.collect()`ing whatsoever, since collecting items, by definition,
111/// expects them to coëxist (within the collection)).
112///
113/// - For instance, there won't be a `for item in iter {` sugar on these
114/// things, since that `for` sugar currently only blesses the stdlib
115/// [`Iterator`] trait.
116///
117/// That being said, `while let Some(item) = iter.next() {` works just
118/// as well, to be honest.
119///
120/// - but the dual / other side of that API restriction is that it is way
121/// simpler / less constraining, _for implementors_, to implement this
122/// trait.
123///
124/// The canonical example illustrating this difference is [`windows_mut()`][
125/// constructors::windows_mut()], which is both an intuitive "iterator" we
126/// can think of, and yet something for which it is _impossible_ to
127/// implement [`Iterator`].
128///
129/// ## A Generic Associated Type
130///
131/// The core definition of this trait is thus:
132///
133/** - ```rust ,ignore
134 #![feature(generic_associated_types)]
135
136 trait LendingIterator {
137 type Item<'next>
138 where
139 Self : 'next,
140 ;
141
142 fn next<'next> (
143 self: &'next mut Self, // <- `Self : 'next` indeed!
144 ) -> Option<Self::Item<'next>>
145 ;
146 }
147 ``` */
148///
149/// As you can see, it involves that more complex `type Item` definition, which
150/// is called a _generic associated type_ (GAT for short), and, it _currently_
151/// requires the `nightly`-only `feature(generic_associated_types)`.
152///
153/// –Then how come this crate can work on stable?— you may ask.
154///
155/// The answer is that [(lifetime)-GATs can actually be emulated in stable Rust
156/// through some extra slightly convoluted hoops][`::nougat`].
157///
158/// [`::nougat`]: https://docs.rs/nougat
159///
160/// That's why this crate uses those techniques (and the crate featuring them,
161/// [`::nougat`]), to achieve Stable Rust support:
162///
163/** - ```rust
164 #[::nougat::gat] // 👈 Add this and now It Just Works™ on stable.
165 trait LendingIterator {
166 type Item<'next>
167 where
168 Self : 'next,
169 ;
170
171 fn next<'next> (
172 self: &'next mut Self,
173 ) -> Option<Self::Item<'next>>
174 ;
175 }
176 ``` */
177///
178/// It does come with a few caveats, though: **the `LendingIterator::Item` item
179/// is no longer really nameable**, at least not _directly_.
180///
181/// - The current implementation of [`::nougat`] uses a helper _higher-order_
182/// super-trait, called
183/// <code>for\<\'any\> [LendingIteratorඞItem]\<\'any\></code>, which has,
184/// itself, a non-generic associated type, `::T`. That way,
185/// `LendingIteratorඞItem<'next>::T` plays the role of
186/// `LendingIterator::Item<'next>`.
187///
188/// **BUT THIS MAY change within semver-compatible changes of `nougat`**
189///
190/// That's why that path should never be used, directly, by downstream code.
191///
192/// The only reason I am even talking about it and not having it
193/// `#[doc(hidden)]` is that exposing it makes understanding the signatures
194/// of the adapters multiple order of magnitude easier.
195///
196/// Hence the following "rules":
197///
198/// - Use <code>[Item]\<\'_, I\></code> instead of `I::Item<'_>`.
199///
200/// - you could technically import the `Gat!` macro from the `::nougat`
201/// crate, and then use `Gat!(I::Item<'_>)` (this is how this crate
202/// manages to define [`Item`], for instance). But it seems less
203/// convenient than a type alias.
204///
205/// - within a `#[gat]`-annotated `trait` or `impl`, most of the
206/// `…::Item<'_>` mentions will automagically be amended by the macro
207/// (which is why the previous snippet works, despite its usage
208/// of `Self::Item<'next>`).
209///
210/// - If implementing the trait yourself, you need to apply
211/// <code>[#\[gat\]][crate::gat]</code> to the `impl` yourself.
212///
213/// - If reëxporting the trait yourself, you need to also apply
214/// <code>[#\[gat(Item)\]][crate::gat]</code> to the `use` statement as
215/// well, so people can implement the trait through the new path.
216///
217/// - [`LendingIterator`] is not really `dyn`-friendly (although IIUC, with
218/// `feature(generic_associated_types)` it wouldn't have been either).
219///
220/// But you can use <code>dyn [LendingIteratorDyn]\<Item = …\> + …</code>
221/// instead, which has been designed with `dyn`-friendlyness in mind 🙂.
222///
223/// </details>
224$($($if_not_better_docs)?
225 #[gat]
226)?
227pub
228trait LendingIterator
229where
230 $($($if_better_docs)?
231 Self : for<'next> LendingIteratorඞItem<'next>,
232 )?
233{
234 $($($if_not_better_docs)?
235 type Item<'next>
236 where
237 Self : 'next,
238 ;
239 )?
240
241 /// Query the `next()` `Item` of this `Self` iterator.
242 ///
243 /// [`LendingIterator`] counterpart of [`Iterator::next()`].
244 fn next (
245 self: &'_ mut Self,
246 ) -> Option<Item<'_, Self>>
247 ;
248
249 /// [`LendingIterator`] counterpart of [`Iterator::filter()`].
250 fn filter<F> (
251 self: Self,
252 should_yield: F,
253 ) -> Filter<Self, F>
254 where
255 Self : Sized,
256 F : FnMut(&'_ Item<'_, Self>) -> bool,
257 {
258 Filter { iter: self, should_yield }
259 }
260
261 /// [`LendingIterator`] counterpart of [`Iterator::for_each()`].
262 fn for_each<> (
263 self: Self,
264 mut f: impl FnMut(Item<'_, Self>),
265 )
266 where
267 Self : Sized,
268 {
269 self.fold((), |(), item| f(item))
270 }
271
272 /// [`LendingIterator`] counterpart of [`Iterator::fold()`].
273 fn fold<Acc> (
274 mut self: Self,
275 acc: Acc,
276 mut f: impl FnMut(Acc, Item<'_, Self>) -> Acc,
277 ) -> Acc
278 where
279 Self : Sized,
280 {
281 self.try_fold(acc, |acc, item| Ok(f(acc, item)))
282 .unwrap_or_else(|unreachable: ǃ| unreachable)
283 }
284
285 /// [`LendingIterator`] counterpart of [`Iterator::try_for_each()`].
286 fn try_for_each<Err> (
287 self: &'_ mut Self,
288 mut f: impl FnMut(Item<'_, Self>) -> Result<(), Err>,
289 ) -> Result<(), Err>
290 {
291 self.try_fold((), |(), item| f(item))
292 }
293
294 /// [`LendingIterator`] counterpart of [`Iterator::try_fold()`].
295 fn try_fold<Acc, Err> (
296 self: &'_ mut Self,
297 mut acc: Acc,
298 mut f: impl FnMut(Acc, Item<'_, Self>) -> Result<Acc, Err>,
299 ) -> Result<Acc, Err>
300 {
301 while let Some(item) = self.next() {
302 acc = f(acc, item)?;
303 }
304 Ok(acc)
305 }
306
307 /// [`LendingIterator`] counterpart of [`Iterator::all()`].
308 fn all<> (
309 self: &'_ mut Self,
310 mut predicate: impl FnMut(Item<'_, Self>) -> bool,
311 ) -> bool
312 where
313 Self : Sized,
314 {
315 self.try_for_each(
316 move |item| if predicate(item) {
317 Ok(())
318 } else {
319 Err(())
320 },
321 )
322 .is_ok()
323 }
324
325 /// [`LendingIterator`] counterpart of [`Iterator::any()`].
326 fn any<> (
327 self: &'_ mut Self,
328 mut predicate: impl FnMut(Item<'_, Self>) -> bool,
329 ) -> bool
330 where
331 Self : Sized,
332 {
333 self.all(move |item| predicate(item).not())
334 .not()
335 }
336
337 /// [`LendingIterator`] counterpart of [`Iterator::by_ref()`].
338 fn by_ref<> (self: &'_ mut Self)
339 -> &'_ mut Self
340 where
341 Self : Sized,
342 {
343 self
344 }
345
346 /// [`LendingIterator`] counterpart of [`Iterator::count()`].
347 fn count<> (self: Self)
348 -> usize
349 where
350 Self : Sized,
351 {
352 self.fold(0_usize, |acc, _| acc + 1)
353 }
354
355 /// [`LendingIterator`] counterpart of [`Iterator::find()`].
356 fn find<'find> (
357 self: &'find mut Self,
358 mut predicate: impl 'find + FnMut(&Item<'_, Self>) -> bool,
359 ) -> Option<Item<'find, Self>>
360 where
361 Self : Sized,
362 {
363 use ::polonius_the_crab::prelude::*;
364 let mut this = self;
365 polonius_loop!(|this| -> Option<Item<'polonius, Self>> {
366 let ret = this.next();
367 if matches!(ret, Some(ref it) if predicate(it).not()) {
368 polonius_continue!();
369 }
370 polonius_return!(ret);
371 })
372 }
373
374 /// [`LendingIterator`] counterpart of [`Iterator::fuse()`].
375 fn fuse (self: Self)
376 -> Fuse<Self>
377 where
378 Self : Sized,
379 {
380 Fuse(Some(self))
381 }
382
383 /// [`LendingIterator`] counterpart of [`Iterator::nth()`].
384 fn nth (
385 self: &'_ mut Self,
386 n: usize,
387 ) -> Option<Item<'_, Self>>
388 {
389 if let Some(n_minus_one) = n.checked_sub(1) {
390 self.skip(n_minus_one);
391 }
392 self.next()
393 }
394
395 /// [`LendingIterator`] counterpart of [`Iterator::position()`].
396 fn position<F> (
397 self: &'_ mut Self,
398 mut predicate: impl FnMut(Item<'_, Self>) -> bool,
399 ) -> Option<usize>
400 where
401 Self : Sized,
402 {
403 match
404 self.try_fold(0, |i, item| if predicate(item) {
405 Err(i)
406 } else {
407 Ok(i + 1)
408 })
409 {
410 | Err(position) => Some(position),
411 | Ok(_) => None,
412 }
413 }
414
415 /// [`LendingIterator`] counterpart of [`Iterator::skip()`].
416 fn skip (
417 self: Self,
418 count: usize,
419 ) -> Skip<Self>
420 where
421 Self : Sized,
422 {
423 Skip {
424 iter: self,
425 to_skip: count.try_into().ok(),
426 }
427 }
428
429 /// [`LendingIterator`] counterpart of [`Iterator::skip_while()`].
430 #[cfg(TODO)]
431 fn skip_while<F> (
432 self: Self,
433 predicate: F,
434 ) -> SkipWhile<Self, F>
435 where
436 F : FnMut(Item<'_, Self>) -> bool,
437 Self : Sized,
438 {
439 SkipWhile { iter: self, predicate }
440 }
441
442 /// [`LendingIterator`] counterpart of [`Iterator::take()`].
443 fn take (
444 self: Self,
445 count: usize,
446 ) -> Take<Self>
447 where
448 Self : Sized,
449 {
450 Take {
451 iter: self,
452 remaining: count,
453 }
454 }
455
456 /// [`LendingIterator`] counterpart of [`Iterator::take_while()`].
457 #[cfg(TODO)]
458 fn take_while<F> (
459 self: Self,
460 f: F,
461 ) -> TakeWhile<Self, F>
462 where
463 F : FnMut(&Self::Item) -> bool,
464 Self : Sized,
465 {
466 TakeWhile(self)
467 }
468
469 /// [`LendingIterator`] counterpart of [`Iterator::map()`].
470 ///
471 /// - **Turbofishing the `NewItemType` is mandatory**, otherwise you'll
472 /// run into issues with non-higher-order closures.
473 ///
474 /// See the module-level documentation of [`crate::higher_kinded_types`]
475 /// for more info.
476 ///
477 /// But the TL,DR is that you'd use it as:
478 ///
479 /// <code>lending_iter.map::\<[HKT!]\(ReturnType\<\'_\>\), _>\(</code>
480 ///
481 /// - the second idiosyncracy is that, for technical reasons[^1] related
482 /// to the maximally generic aspect of this API, the closure itself
483 /// cannot just be a `Self::Item<'_> -> Feed<'_, NewItemType>` closure,
484 /// and instead, requires that an extra `[]` dummy parameter be part
485 /// of the signature:
486 ///
487 /// ```rust
488 /// # #[cfg(any)] macro_rules! ignore { /*
489 /// lending_iter.map::<HKT…, _>(|[], item| { … })
490 /// 👆
491 /// # */ }
492 /// ```
493 ///
494 /// [^1]: In the case where `Self::Item<'_>` does _not_ depend on `'_`, the
495 /// return type then technically can't depend on it either, so Rust
496 /// complains about this (in a rather obtuse fashion). We solve this by
497 /// requiring that extra `[]` parameter which acts as a convenient-to-write
498 /// `PhantomData` which does depend on `'_`.
499 fn map<NewItemType : HKT, F> (
500 self: Self,
501 f: F,
502 ) -> Map<Self, F, NewItemType>
503 where
504 for<'next>
505 F : FnMut(
506 [&'next Self; 0],
507 Item<'next, Self>,
508 ) -> A!(NewItemType<'next>)
509 ,
510 Self : Sized,
511 {
512 Map { iter: self, map: f, _phantom_ty: <_>::default() }
513 }
514
515 pervasive_hkt_choices! {
516 (map, Map)(
517 /// Convenience method: same as [`.map()`][Self::map()], but for
518 /// hard-coding the `HKT` parameter to
519 /// <code>[HKTRef]\<R\> = [HKT!]\(\&R\)</code>.
520 ///
521 /// This alleviates the call-sites (no more turbofishing needed!)
522 /// for such pervasive use cases 🙂
523 map_to_ref: [R : ?Sized], HKTRef<R>, -> &'any R,
524 /// Convenience method: same as [`.map()`][Self::map()], but for
525 /// hard-coding the `HKT` parameter to
526 /// <code>[HKTRefMut]\<R\> = [HKT!]\(\&mut R\)</code>.
527 ///
528 /// This alleviates the call-sites (no more turbofishing needed!)
529 /// for such pervasive use cases 🙂
530 map_to_mut: [R : ?Sized], HKTRefMut<R>, -> &'any mut R,
531 ),
532 }
533
534 /// Convenience shorthand for
535 /// <code>[.map…\(…\)][Self::map()][.into_iter()][Self::into_iter()]</code>.
536 ///
537 /// When the return type of the `.map()` closure is not lending
538 /// / borrowing from `*self`, it becomes possible to call
539 /// [.into_iter()][Self::into_iter()] on it right away.
540 ///
541 /// Moreover, it makes the `[], ` closure arg hack no longer necessary.
542 ///
543 /// This convenience function encompasses both things, thence returning
544 /// an [`Iterator`] (not a [`LendingIterator`]!).
545 fn map_into_iter<F, NonLendingItem> (
546 self: Self,
547 f: F,
548 ) -> MapIntoIter<Self, F>
549 where
550 F : FnMut(Item<'_, Self>) -> NonLendingItem,
551 Self : Sized,
552 {
553 MapIntoIter(self, f)
554 }
555
556 /// [`LendingIterator`] counterpart of [`Iterator::filter_map()`].
557 ///
558 /// All the caveats and remarks of [`.map()`][Self::map()] apply, go check
559 /// them up.
560 fn filter_map<NewItemType : HKT, F> (
561 self: Self,
562 f: F,
563 ) -> FilterMap<Self, F, NewItemType>
564 where
565 for<'next>
566 F : FnMut(
567 [&'next Self; 0],
568 Item<'next, Self>,
569 ) -> Option<A!(NewItemType<'next>)>
570 ,
571 Self : Sized,
572 {
573 FilterMap { iter: self, map: f, _phantom_ty: <_>::default() }
574 }
575
576 pervasive_hkt_choices! {
577 (filter_map, FilterMap)(
578 /// Convenience method: same as
579 /// [`.filter_map()`][Self::filter_map()], but for hard-coding the
580 /// `HKT` parameter to <code>[HKTRef]\<R\> = [HKT!]\(\&R\)</code>.
581 ///
582 /// All the caveats and remarks of
583 /// [`.map_to_ref()`][Self::map_to_ref()] apply, go check them up.
584 filter_map_to_ref: [R : ?Sized], HKTRef<R>, -> Option<&'any R>,
585
586 /// Convenience method: same as
587 /// [`.filter_map()`][Self::filter_map()], but for hard-coding the
588 /// `HKT` parameter to <code>[HKTRefMut]\<R\> = [HKT!]\(\&mut R\)</code>.
589 ///
590 /// All the caveats and remarks of
591 /// [`.map_to_mut()`][Self::map_to_mut()] apply, go check them up.
592 filter_map_to_mut: [R : ?Sized], HKTRefMut<R>, -> Option<&'any mut R>,
593 ),
594 }
595
596 /// Convenience shorthand for
597 /// <code>[.filter_map…\(…\)][Self::filter_map()][.into_iter()][Self::into_iter()]</code>.
598 ///
599 /// When the return type of the `.filter_map()` closure is not lending
600 /// / borrowing from `*self`, it becomes possible to call
601 /// [.into_iter()][Self::into_iter()] on it right away.
602 ///
603 /// Moreover, it makes the `[], ` closure arg hack no longer necessary.
604 ///
605 /// This convenience function encompasses both things, thence returning
606 /// an [`Iterator`] (not a [`LendingIterator`]!).
607 fn filter_map_into_iter<F, NonLendingItem> (
608 self: Self,
609 f: F,
610 ) -> FilterMapIntoIter<Self, F>
611 where
612 F : FnMut(Item<'_, Self>) -> Option<NonLendingItem>,
613 Self : Sized,
614 {
615 FilterMapIntoIter(self, f)
616 }
617
618 /// Convert a <code>Self : [LendingIterator]</code> into an [`Iterator`],
619 /// **provided `Self::Item<'_>` does not depend on `'_`**.
620 fn into_iter<Item> (
621 self: Self,
622 ) -> IntoIter<Self>
623 where
624 Self : for<'any> LendingIteratorඞItem<'any, T = Item>,
625 Self : Sized,
626 {
627 IntoIter(self)
628 }
629
630 /// Converts this [`LendingIterator`] into a
631 /// <code>[Box][::alloc::boxed::Box]\<dyn [LendingIteratorDyn]…\></code>.
632 ///
633 /// Note that the return `dyn Trait` will not be `Send` or implement any
634 /// other auto-traits. For a more general albeit harder-on-type-inference
635 /// alternative, see [`.dyn_boxed_auto()`][Self::dyn_boxed_auto()].
636 #[apply(cfg_alloc)]
637 fn dyn_boxed<'usability> (
638 self: Self
639 ) -> ::alloc::boxed::Box<dyn
640 'usability + LendingIteratorDyn<Item = HKTItem<Self>>
641 >
642 where
643 Self : 'usability,
644 Self : Sized,
645 {
646 ::alloc::boxed::Box::new(self)
647 }
648
649 /// Converts this [`LendingIterator`] into a
650 /// <code>[Box][::alloc::boxed::Box]\<dyn [LendingIteratorDyn]…\></code>.
651 ///
652 /// In order for it to work, the `Item` parameter has to be provided
653 /// (probably funneled through a [`CanonicalHKT`]), as well as an explicit
654 /// "landing type" (inference will probably fail to figure it out!).
655 ///
656 /// That is, `BoxedDynLendingIterator` is expected to be of the form:
657 ///
658 /// <code>[Box]\<dyn \'lt \[+ Send\] \[+ Sync\] + [LendingIteratorDyn]\<Item = [CanonicalHKT]\<…\>\>\></code>
659 ///
660 /// [Box]: ::alloc::boxed::Box
661 /// [CanonicalHKT]: crate::prelude::CanonicalHKT
662 #[apply(cfg_alloc)]
663 fn dyn_boxed_auto<BoxedDynLendingIterator, Item : HKT> (self: Self)
664 -> BoxedDynLendingIterator
665 where
666 Self : Sized + DynCoerce<BoxedDynLendingIterator, Item>,
667 {
668 Self::coerce(self)
669 }
670}
671)}
672
673macro_rules! pervasive_hkt_choices {(
674 ($map:ident, $Map:ident)(
675 $(
676 $(#[$attr:meta])*
677 $fname:ident: [$($R:tt)*], $HKT:ty, -> $Ret:ty,
678 )*
679 ) $(,)?
680) => (
681 $(
682 $(#[$attr])*
683 fn $fname<$($R)*, F> (
684 self: Self,
685 f: F,
686 ) -> $Map<Self, F, $HKT>
687 where
688 for<'any>
689 F : FnMut([&'any Self; 0], Item<'any, Self>) -> $Ret
690 ,
691 Self : Sized,
692 {
693 self.$map::<$HKT, F>(f)
694 }
695 )*
696)} use pervasive_hkt_choices;
697
698#[cfg(test)]
699mod tests;