1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
use super::*;
/// `dyn`-friendly (`dyn`-safe) version of [`LendingIterator`].
///
/// It is automagically implemented for all types implementing
/// [`LendingIterator`], and, conversely, [`LendingIterator`] is implemented for
/// <code>dyn [LendingIteratorDyn]</code>.
///
// / # A convenient alias
// /
// / Since <code>dyn \'usability + [LendingIteratorDyn]\<Item = …\></code>, on
// / top of yielding that `dyn` "stutter", is a mouthful, such `dyn Trait` type
// / can be named through the <code>[dynLendingIterator]\<\'usability, …\></code>
// / shorthand alias 🙂.
///
/// ### Limitations
///
/// Beware that such a trait does still not play well with contexts which are
/// generic over the "lending mode" ⚠️
///
/// So, if you intend to unify two heterogeneous [`LendingIterator`] under the
/// same <code>dyn LendingIteratorDyn</code>, make sure to hard-code the
/// dependency on the `'next`-lending lifetime.
///
/// Otherwise you might have to:
/// - involve [`CanonicalHKT`][crate::higher_kinded_types::CanonicalHKT] in
/// your signatures,
/// - and use [`.dyn_boxed_auto()`] rather than the [`.dyn_boxed()`] direct
/// shorthand.
///
/// [`.dyn_boxed_auto()`]: LendingIterator::dyn_boxed_auto
/// [`.dyn_boxed()`]: LendingIterator::dyn_boxed
///
/// ### Example: `dyn` coercion of a _fully generic_ `LendingIterator`:
///
/** - ```rust
use ::lending_iterator::prelude::*;
fn coercions<'T, Item, T> (it: T)
where
Item : HKT,
T : 'T + Send + Sync + LendingIterator,
// THIS IS THE BOUND THAT YOU HAVE TO ADD TO MAKE IT WORK, for some reason:
T : LendingIteratorDyn<Item = CanonicalHKT<Item>>, // 👈
{
match () {
_ => {
let _: Box<dyn 'T + LendingIteratorDyn<Item = CanonicalHKT<Item>>> =
it.dyn_boxed_auto()
;
},
_ => {
let _: Box<dyn 'T + LendingIteratorDyn<Item = CanonicalHKT<Item>> + Send> =
it.dyn_boxed_auto()
;
},
_ => {
let _: Box<dyn 'T + LendingIteratorDyn<Item = CanonicalHKT<Item>> + Sync> =
it.dyn_boxed_auto()
;
},
_ => {
let _: Box<dyn 'T + LendingIteratorDyn<Item = CanonicalHKT<Item>> + Send + Sync> =
it.dyn_boxed_auto()
;
},
}
}
``` */
///
pub
trait LendingIteratorDyn {
/// Another approach to a `GAT` in stable Rust: use a classic associated
/// type, but with a [`HKT`][trait@HKT] bound on it, so that it can still
/// be [fed][`crate::higher_kinded_types::Feed`] a lifetime parameter.
type Item : ?Sized + HKT;
/// A `dyn`-safe version of [`LendingIterator::next()`], using
/// [`Self::Item]`.
///
/// Given that <code>[LendingIteratorDyn] : [LendingIterator]</code>, you
/// should not need to call this function directly: calling `.next()` ought
/// to work just as well.
///
/// - That being said, if defining a `LendingIteratorDyn` subtrait, you
/// may then need to directly call into it.
fn dyn_next (
self: &'_ mut Self,
) -> Option<A!(Self::Item<'_>)>
;
}
/// `impl LendingIterator : LendingIteratorDyn`
impl<T : LendingIterator>
LendingIteratorDyn
for
T
{
type Item = HKTItem<T>;
fn dyn_next<'n> (
self: &'n mut T,
) -> Option<A!(HKTItem<T><'n>)> // a pinch of curry for its flavor 😗👌
{
self.next()
}
}
with_auto_traits! {( $($AutoTraits:tt)* ) => (
/// `dyn LendingIteratorDyn + … : LendingIterator`
#[nou::gat]
impl<'usability, Item : HKT>
LendingIterator
for
(dyn
'usability +
LendingIteratorDyn<Item = Item> +
$($AutoTraits)*
)
{
type Item<'next>
where
Self : 'next,
=
A!(Item<'next>) // <T as LendingIteratorDyn<'next>>::Item
;
fn next<'next> (
self: &'next mut (dyn
'usability +
LendingIteratorDyn<Item = Item> +
$($AutoTraits)*
),
) -> Option<A!(Item<'next>)> // Self::Item<'_>>
{
self.dyn_next()
}
}
)}
/// "Lift" and convert an <code>impl [LendingIterator]</code> into an
/// <code>impl [HKT][trait@HKT]</code>.
///
/// ```rust
/// # #[cfg(any())] macro_rules! ignore {
/// type HKTItem<I : LendingIterator> = HKT!(Item<'_, I>);
/// # }
/// ```
///
/// - It is therefore a [`CanonicalHKT`] (no need to apply it again).
///
/// The main property of this alias, and thus the connection between
/// <code>impl [LendingIterator]</code>s and <code>impl [HKT][trait@HKT]</code>,
/// is that:
///
/// ```rust
/// # #[cfg(any())] macro_rules! ignore {
/// // Given some `<'n, I : LendingIterator>`:
/// Apply!(HKTItem<I><'n>) = Feed<'n, HKT!(Item<'_, T>)> = Item<'n, I>
/// # }
/// ```
#[allow(type_alias_bounds)]
pub
type HKTItem<I : ?Sized + LendingIterator> =
HKT!(Item<'_, I>)
;
#[doc(hidden)] // Let's not overwhelm users of the crate with info.
pub
trait DynCoerce<T, Item> : Sized {
fn coerce(self: Self) -> T;
}
#[apply(cfg_alloc)]
r#dyn::with_auto_traits! {( $($AutoTraits:tt)* ) => (
impl<'I, I : 'I, Item>
DynCoerce<
::alloc::boxed::Box<dyn
'I + LendingIteratorDyn<Item = CanonicalHKT<Item>> +
$($AutoTraits)*
>,
Item,
>
for
I
where
Item : HKT,
I : LendingIteratorDyn<Item = CanonicalHKT<Item>>,
I : $($AutoTraits)* ,
{
fn coerce (self: I)
-> ::alloc::boxed::Box<dyn
'I + LendingIteratorDyn<Item = CanonicalHKT<Item>> +
$($AutoTraits)*
>
{
::alloc::boxed::Box::new(self)
}
}
)}
macro_rules! with_auto_traits {( $($rules:tt)* ) => (
macro_rules! __emit__ { $($rules)* }
__emit__! {}
__emit__! { Send }
__emit__! { Sync }
__emit__! { Send + Sync }
)} pub(in crate) use with_auto_traits;
#[cfg(any(doc, test))]
mod tests;