use std::future::Future;
use std::marker::Unpin;
use std::marker::{Send, Sync};
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use crate::{Generator, GeneratorState};
pub fn generator_mem<R, Y>() -> (Rc<Option<R>>, Rc<Option<Y>>) {
(Rc::new(None), Rc::new(None))
}
struct YieldFuture<R> {
__resume: Rc<Option<R>>,
}
impl<R> Future for YieldFuture<R> {
type Output = R;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(r) = unsafe {
(Rc::as_ptr(&mut Pin::into_inner(self).__resume) as *mut Option<R>)
.as_mut()
.expect("not null")
.take()
} {
Poll::Ready(r)
} else {
Poll::Pending
}
}
}
pub fn yield_future<R, Y>(
__resume: Rc<Option<R>>,
mut __yield: Rc<Option<Y>>,
val: Y,
) -> impl Future<Output = R> {
let __yield = unsafe {
(Rc::as_ptr(&mut __yield) as *mut Option<Y>)
.as_mut()
.expect("not null")
};
*__yield = Some(val);
YieldFuture { __resume }
}
fn null_waker() -> Waker {
unsafe fn clone(_: *const ()) -> RawWaker {
RawWaker::new(&UNIT, &VTABLE)
}
unsafe fn nothing(_: *const ()) {}
const UNIT: () = ();
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, nothing, nothing, nothing);
let raw_waker = RawWaker::new(&UNIT, &VTABLE);
unsafe { Waker::from_raw(raw_waker) }
}
struct GeneratorImpl<R, Y, F> {
__resume: Rc<Option<R>>,
__yield: Rc<Option<Y>>,
future: Pin<Box<F>>,
done: bool,
}
impl<R, Y, F> Unpin for GeneratorImpl<R, Y, F> {}
unsafe impl<R, Y, F> Send for GeneratorImpl<R, Y, F>
where
R: Send,
Y: Send,
F: Send,
{
}
unsafe impl<R, Y, F> Sync for GeneratorImpl<R, Y, F>
where
R: Sync,
Y: Sync,
F: Sync,
{
}
impl<R, Y, F> Generator<R> for GeneratorImpl<R, Y, F>
where
F: Future,
{
type Yield = Y;
type Return = F::Output;
fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
let me = Pin::get_mut(self);
if me.done {
panic!("Attempted to resume an already completed generator");
}
let waker = null_waker();
let mut ctx = Context::from_waker(&waker);
unsafe {
let resume = (Rc::as_ptr(&mut me.__resume) as *mut Option<R>)
.as_mut()
.expect("not null");
*resume = Some(arg);
}
let result = me.future.as_mut().poll(&mut ctx);
match result {
Poll::Pending => {
let val = unsafe {
(Rc::as_ptr(&mut me.__yield) as *mut Option<Y>)
.as_mut()
.expect("not null")
.take()
}
.expect("generator compat future returned pending without setting yield");
GeneratorState::Yielded(val)
}
Poll::Ready(val) => {
me.done = true;
GeneratorState::Complete(val)
}
}
}
}
pub fn generator_for<R, Y, Ret, F>(
__resume: Rc<Option<R>>,
__yield: Rc<Option<Y>>,
future: F,
) -> impl Generator<R, Yield = Y, Return = Ret>
where
F: Future<Output = Ret>,
{
GeneratorImpl {
__resume,
__yield,
future: Box::pin(future),
done: false,
}
}