use crate::{
core::{advance, async_advance, Airlock as _, Next},
ext::MaybeUninitExt,
ops::{Coroutine, GeneratorState},
stack::engine::{Airlock, Co},
};
use std::{future::Future, mem, pin::Pin, ptr};
pub struct Shelf<Y, R, F: Future>(mem::MaybeUninit<State<Y, R, F>>);
struct State<Y, R, F: Future> {
airlock: Airlock<Y, R>,
future: F,
}
impl<Y, R, F: Future> Shelf<Y, R, F> {
#[must_use]
pub fn new() -> Self {
Self(mem::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> {
state: Pin<&'s mut State<Y, R, 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 p = &mut *shelf.0.as_mut_ptr() as *mut State<Y, R, F>;
let airlock = Airlock::default();
ptr::write(&mut (*p).airlock, airlock);
let future = producer(Co::new(&(*p).airlock));
ptr::write(&mut (*p).future, future);
let state = Pin::new_unchecked(shelf.0.assume_init_get_mut());
Self { state }
}
pub fn resume_with(&mut self, arg: R) -> GeneratorState<Y, F::Output> {
let (future, airlock) = self.project();
airlock.replace(Next::Resume(arg));
advance(future, &airlock)
}
fn project(&mut self) -> (Pin<&mut F>, &Airlock<Y, R>) {
unsafe {
let state = self.state.as_mut().get_unchecked_mut();
let future = Pin::new_unchecked(&mut state.future);
let airlock = &state.airlock;
(future, airlock)
}
}
}
impl<'s, Y, R, F: Future> Drop for Gen<'s, Y, R, F> {
fn drop(&mut self) {
unsafe {
let state = self.state.as_mut().get_unchecked_mut();
ptr::drop_in_place(&mut state.future);
ptr::drop_in_place(&mut state.airlock);
}
}
}
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>> + '_ {
let (future, airlock) = self.project();
airlock.replace(Next::Resume(()));
async_advance(future, 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)
}
}