use std::{
cell::UnsafeCell,
future::{poll_fn, Future},
pin::Pin,
ptr::NonNull,
task::{Context, Poll},
};
use crate::{AsyncGenerator, AsyncIter, GeneratorState};
pub fn gen<Fut, Y, R>(fut: impl FnOnce(Yielder<Y>) -> Fut) -> AsyncGen<Fut, Y>
where
Fut: Future<Output = Return<R>>,
{
let cell = Box::new(UnsafeCell::new(None));
let data = Box::leak(cell).into();
let fut = fut(Yielder {
cell: Cell { data },
});
AsyncGen {
cell: Cell { data },
fut,
}
}
struct Cell<Y> {
data: NonNull<UnsafeCell<Option<Y>>>,
}
impl<Y> Cell<Y> {
#[inline]
fn data(&self) -> &UnsafeCell<Option<Y>> {
unsafe { self.data.as_ref() }
}
}
unsafe impl<Y: Send> Send for Cell<Y> {}
unsafe impl<Y: Send + Sync> Sync for Cell<Y> {}
#[repr(transparent)]
pub struct Return<T = ()>(T);
#[doc(hidden)]
pub struct Yielder<Y = ()> {
cell: Cell<Y>,
}
impl<Y> Yielder<Y> {
pub fn yield_(&mut self, val: Y) -> impl Future<Output = ()> + use<'_, Y> {
unsafe {
*self.cell.data().get() = Some(val);
}
poll_fn(|_| {
if unsafe { (*self.cell.data().get()).is_some() } {
return Poll::Pending;
}
Poll::Ready(())
})
}
#[inline]
pub fn return_<R>(self, v: R) -> Return<R> {
Return(v)
}
}
pub struct AsyncGen<Fut, Y> {
cell: Cell<Y>,
fut: Fut,
}
impl<Fut, Y> Drop for AsyncGen<Fut, Y> {
fn drop(&mut self) {
unsafe {
drop(Box::from_raw(self.cell.data.as_ptr()));
};
}
}
impl<Fut, Y, R> AsyncGen<Fut, Y>
where
Fut: Future<Output = Return<R>>,
{
pub fn poll_resume(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<GeneratorState<Y, R>> {
let me = unsafe { self.get_unchecked_mut() };
match unsafe { Pin::new_unchecked(&mut me.fut).poll(cx) } {
Poll::Ready(Return(val)) => Poll::Ready(GeneratorState::Complete(val)),
Poll::Pending => {
unsafe {
if let Some(val) = (*me.cell.data().get()).take() {
return Poll::Ready(GeneratorState::Yielded(val));
}
}
Poll::Pending
}
}
}
pub async fn resume(self: &mut Pin<&mut Self>) -> GeneratorState<Y, R> {
poll_fn(|cx| self.as_mut().poll_resume(cx)).await
}
}
impl<Fut, Y> AsyncGen<Fut, Y>
where
Fut: Future<Output = Return<()>>,
{
pub fn into_async_iter(self) -> AsyncIter<Self> {
AsyncIter::from(self)
}
pub fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Y>> {
let me = unsafe { self.get_unchecked_mut() };
match unsafe { Pin::new_unchecked(&mut me.fut).poll(cx) } {
Poll::Ready(Return(())) => Poll::Ready(None),
Poll::Pending => {
unsafe {
if let Some(val) = (*me.cell.data().get()).take() {
return Poll::Ready(Some(val));
}
}
Poll::Pending
}
}
}
}
impl<Fut, Y, R> AsyncGenerator for AsyncGen<Fut, Y>
where
Fut: Future<Output = Return<R>>,
{
type Yield = Y;
type Return = R;
fn poll_resume(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<GeneratorState<Self::Yield, Self::Return>> {
AsyncGen::poll_resume(self, cx)
}
}