use core::fmt::{self, Debug, Formatter};
use core::ops::{Generator, GeneratorState};
use core::pin::Pin;
use crate::NoData;
pub trait IntoGenerator {
type Resume;
type Yield;
type Return;
type Generator: Generator<Self::Resume, Yield = Self::Yield, Return = Self::Return>;
#[must_use]
fn into_generator(self) -> Self::Generator;
}
impl<I: Iterator> IntoGenerator for I {
type Resume = ();
type Yield = I::Item;
type Return = ();
type Generator = GenIter<I>;
fn into_generator(self) -> Self::Generator {
GenIter::new(self)
}
}
#[derive(Clone, Debug)]
#[repr(transparent)]
pub struct GenIter<I: Iterator> {
iter: I,
}
impl<I: Iterator> GenIter<I> {
#[must_use]
pub fn new(iter: I) -> Self {
Self { iter }
}
#[must_use]
pub fn into_inner(self) -> I {
self.iter
}
}
impl<I: Iterator> Generator<()> for GenIter<I> {
type Yield = I::Item;
type Return = ();
fn resume(self: Pin<&mut Self>, _arg: ()) -> GeneratorState<Self::Yield, Self::Return> {
match unsafe { self.get_unchecked_mut() }.iter.next() {
Some(item) => GeneratorState::Yielded(item),
None => GeneratorState::Complete(()),
}
}
}
#[repr(transparent)]
pub struct Gen<R, G: Generator<R>> {
gen: G,
_arg: NoData<R>,
}
impl<R, G: Generator<R>> Gen<R, G> {
#[must_use]
pub fn new(gen: G) -> Self {
Self { gen, _arg: NoData::new() }
}
#[allow(clippy::wrong_self_convention)] #[must_use]
pub fn as_pinned(self: Pin<&mut Self>) -> Pin<&mut G> {
unsafe { self.map_unchecked_mut(|pin| &mut pin.gen) }
}
#[must_use]
pub fn into_inner(self) -> G {
self.gen
}
}
impl<R, G: Generator<R> + Debug> Debug for Gen<R, G> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.gen.fmt(f)
}
}
impl<R, G: Generator<R>> From<G> for Gen<R, G> {
fn from(gen: G) -> Self {
Self::new(gen)
}
}
impl<R, G: Generator<R>> Generator<R> for Gen<R, G> {
type Yield = G::Yield;
type Return = G::Return;
fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
self.as_pinned().resume(arg)
}
}
impl<R, G: Generator<R>> IntoGenerator for Gen<R, G> {
type Resume = R;
type Yield = G::Yield;
type Return = G::Return;
type Generator = G;
fn into_generator(self) -> Self::Generator {
self.gen
}
}