use std::{future::Future, mem::MaybeUninit, pin::Pin, ptr};
use crate::{
core::{advance, async_advance, Airlock as _, Next},
ops::{Coroutine, GeneratorState},
stack::engine::{Airlock, Co},
};
pub struct Shelf<Y, R, F: Future> {
airlock: Airlock<Y, R>,
future: MaybeUninit<F>,
}
impl<Y, R, F: Future> Shelf<Y, R, F> {
#[must_use]
pub fn new() -> Self {
Self {
airlock: Airlock::default(),
future: MaybeUninit::uninit(),
}
}
}
impl<Y, R, F: Future> Default for Shelf<Y, R, F> {
#[must_use]
fn default() -> Self {
Self::new()
}
}
pub struct Gen<'s, Y, R, F: Future> {
airlock: &'s Airlock<Y, R>,
future: Pin<&'s mut F>,
}
impl<'s, Y, R, F: Future> Gen<'s, Y, R, F> {
pub unsafe fn new(
shelf: &'s mut Shelf<Y, R, F>,
producer: impl FnOnce(Co<'s, Y, R>) -> F,
) -> Self {
let airlock = &shelf.airlock;
shelf.future.as_mut_ptr().write(producer(Co::new(airlock)));
let init = &mut *shelf.future.as_mut_ptr();
Self {
airlock,
future: Pin::new_unchecked(init),
}
}
pub fn resume_with(&mut self, arg: R) -> GeneratorState<Y, F::Output> {
self.airlock.replace(Next::Resume(arg));
advance(self.future.as_mut(), &self.airlock)
}
}
impl<'s, Y, R, F: Future> Drop for Gen<'s, Y, R, F> {
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(self.future.as_mut().get_unchecked_mut());
}
}
}
impl<'s, Y, F: Future> Gen<'s, Y, (), F> {
pub fn resume(&mut self) -> GeneratorState<Y, F::Output> {
self.resume_with(())
}
pub fn async_resume(
&mut self,
) -> impl Future<Output = GeneratorState<Y, F::Output>> + '_ {
self.airlock.replace(Next::Resume(()));
async_advance(self.future.as_mut(), self.airlock)
}
}
impl<'s, Y, R, F: Future> Coroutine for Gen<'s, Y, R, F> {
type Yield = Y;
type Resume = R;
type Return = F::Output;
fn resume_with(
self: Pin<&mut Self>,
arg: R,
) -> GeneratorState<Self::Yield, Self::Return> {
let this = unsafe { self.get_unchecked_mut() };
this.resume_with(arg)
}
}