use core::{
cell::UnsafeCell,
future::{
Future,
poll_fn,
},
hint::unreachable_unchecked,
marker::{
PhantomData,
PhantomPinned,
},
mem,
pin::Pin,
task::{
Poll,
Context,
Waker,
},
};
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use core::{
cell::Cell,
mem::MaybeUninit,
ptr::{
addr_of,
read,
null_mut,
},
};
#[cfg(feature = "alloc")]
use alloc::{
collections::VecDeque,
rc::{
Rc,
Weak,
},
};
mod context;
trait AsyncFnOnce<Arg> {}
impl<F, A, R: Future> AsyncFnOnce<(A, )> for F
where
F: FnOnce(A) -> R,
{}
impl<F, A, B, R: Future> AsyncFnOnce<(A, B, )> for F
where
F: FnOnce(A, B) -> R,
{}
pub unsafe trait RemitWithLifetime<T, X> {}
unsafe impl<T, F> RemitWithLifetime<T, ()> for F
where
F: for<'a> AsyncFnOnce<(Remit<'a, T>, )>,
{}
unsafe impl<T, X, F> RemitWithLifetime<T, (X, )> for F
where
F: for<'a> AsyncFnOnce<(X, Remit<'a, T>, )>,
{}
pub struct Generator<T, P> {
values: UnsafeCell<Values<T>>,
future: Option<P>,
_pin: PhantomPinned,
}
impl<T, P> Generator<T, P> {
pub fn new() -> Self {
Generator {
values: UnsafeCell::new(Values::Missing),
future: None,
_pin: PhantomPinned,
}
}
#[allow(clippy::needless_lifetimes)]
pub fn of<'s, G>(
self: Pin<&'s mut Self>,
gen: G,
) -> GeneratorIterator<'s, T, P>
where
G: RemitWithLifetime<T, ()>,
G: FnOnce(Remit<'static, T>) -> P,
{
let inner = unsafe { self.get_unchecked_mut() };
let value = inner.values.get();
let mode = Mode::Pinned {
value,
_lifetime: PhantomData,
};
let future = gen(Remit(mode));
let future = inner.future.insert(future);
GeneratorIterator {
done: false,
mode,
future,
#[cfg(feature = "alloc")]
_owner: None,
}
}
#[allow(clippy::needless_lifetimes)]
pub fn parameterized<'s, G, X>(
self: Pin<&'s mut Self>,
gen: G,
parameter: X,
) -> GeneratorIterator<'s, T, P>
where
G: RemitWithLifetime<T, (X,)>,
G: FnOnce(X, Remit<'static, T>) -> P,
{
let inner = unsafe { self.get_unchecked_mut() };
let value = inner.values.get();
let mode = Mode::Pinned {
value,
_lifetime: PhantomData,
};
let future = gen(parameter, Remit(mode));
let future = inner.future.insert(future);
GeneratorIterator {
done: false,
mode,
future,
#[cfg(feature = "alloc")]
_owner: None,
}
}
#[cfg(feature = "alloc")]
pub fn boxed(gen: impl FnOnce(Remit<'static, T>) -> P) -> GeneratorIterator<'static, T, P> {
let rc = Rc::new(Cycler {
future: Default::default(),
references: References::new::<P>(),
weak_inner: UnsafeCell::new(MaybeUninit::uninit()),
_pin: Default::default(),
});
let weak = Rc::downgrade(&rc);
let ptr: *mut Weak<Cycler<P, T>> = unsafe { &mut *rc.weak_inner.get() }.write(weak);
rc.references.ptr.set(ptr as _);
let mode = Mode::Boxed(&rc.references);
let future = unsafe { &mut *rc.future.get() }.insert(gen(Remit(mode)));
GeneratorIterator {
done: false,
mode,
future,
_owner: Some(rc),
}
}
}
#[cfg(feature = "alloc")]
struct References<T> {
interchange: UnsafeCell<Values<T>>,
dropper: unsafe fn(*mut ()),
checker: unsafe fn(*mut ()) -> bool,
ptr: Cell<*mut ()>,
}
#[cfg(feature = "alloc")]
impl<T> References<T> {
fn new<P>() -> Self {
References {
interchange: UnsafeCell::new(Values::Missing),
dropper: Cycler::<P, T>::do_inner_drop,
checker: Cycler::<P, T>::is_strong,
ptr: Cell::new(null_mut()),
}
}
}
#[cfg(feature = "alloc")]
struct Cycler<P, T> {
future: UnsafeCell<Option<P>>,
references: References<T>,
weak_inner: UnsafeCell<MaybeUninit<Weak<Cycler<P, T>>>>,
_pin: PhantomPinned,
}
#[cfg(feature = "alloc")]
impl<P, T> Cycler<P, T> {
unsafe fn do_inner_drop(ptr: *mut ()) {
let ptr: *mut Weak<Cycler<P, T>> = ptr as _;
let _: Weak<Cycler<P, T>> = read(ptr);
}
unsafe fn is_strong(ptr: *mut ()) -> bool {
let ptr: *const Weak<Cycler<P, T>> = ptr as _;
(*ptr).strong_count() > 0
}
}
pub struct GeneratorIterator<'a, T, P> {
done: bool,
mode: Mode<'a, T>,
future: *mut P,
#[cfg(feature = "alloc")]
_owner: Option<Rc<Cycler<P, T>>>,
}
impl<T, P: Future<Output=()>> Iterator for GeneratorIterator<'_, T, P> {
type Item = T;
fn next(&mut self) -> Option<T> {
if let Some(value) = self.mode.next() {
return Some(value)
}
if self.done {
return None
}
let waker = unsafe { Waker::from_raw(context::NOOP_WAKER) };
if let Poll::Ready(()) = unsafe { Pin::new_unchecked(&mut *self.future) }.poll(&mut Context::from_waker(&waker)) {
self.done = true;
}
self.mode.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.mode.len();
if self.done {
(len, Some(len))
} else {
(len, None)
}
}
}
enum Values<T> {
Present(T),
Missing,
#[cfg(feature = "alloc")]
Multiple(VecDeque<T>),
}
enum Mode<'a, T> {
Pinned {
value: *mut Values<T>,
_lifetime: PhantomData<&'a ()>,
},
#[cfg(feature = "alloc")]
Boxed(*const References<T>),
}
impl<T> Clone for Mode<'_, T> {
fn clone(&self) -> Self {
*self
}
fn clone_from(&mut self, source: &Self) {
*self = *source
}
}
impl<T> Copy for Mode<'_, T> {}
impl<T> Mode<'_, T> {
#[inline(always)]
fn values(&self) -> *mut Values<T> {
match *self {
Mode::Pinned {
value,
..
} => value,
#[cfg(feature = "alloc")]
Mode::Boxed(ptr) => unsafe { &*addr_of!((*ptr).interchange) }.get()
}
}
#[inline(always)]
fn next(&self) -> Option<T> {
Self::next_inner(unsafe { &mut *self.values() })
}
fn next_inner(values: &mut Values<T>) -> Option<T> {
use Values::*;
match values {
Missing => None,
Present(_) =>
if let Present(value) = mem::replace(values, Missing) {
Some(value)
} else { unsafe { unreachable_unchecked() } },
#[cfg(feature = "alloc")]
Multiple(list) => list.pop_front(),
}
}
#[inline(always)]
fn push(&self, value: T) {
let _ = Self::push_inner(unsafe { &mut *self.values() }, value);
}
#[cfg(feature = "alloc")]
fn push_inner(values: &mut Values<T>, value: T) {
use Values::*;
match values {
Missing => *values = Present(value),
Present(_) => {
let Present(old) = mem::replace(values, Missing)
else { unsafe { unreachable_unchecked() } };
let mut list = VecDeque::with_capacity(2);
list.push_back(old);
list.push_back(value);
*values = Multiple(list);
},
Multiple(list) => list.push_back(value),
}
}
#[cfg(not(feature = "alloc"))]
fn push_inner(values: &mut Values<T>, value: T) -> Values<T> {
mem::replace(values, Values::Present(value))
}
#[inline(always)]
fn len(&self) -> usize {
Self::len_inner(unsafe { &*self.values() })
}
fn len_inner(values: &Values<T>) -> usize {
use Values::*;
match values {
Present(_) => 1,
Missing => 0,
#[cfg(feature = "alloc")]
Multiple(list) => list.len(),
}
}
#[inline(always)]
fn is_empty(&self) -> bool {
Self::is_empty_inner(unsafe { &*self.values() })
}
fn is_empty_inner(values: &Values<T>) -> bool {
use Values::*;
match values {
Present(_) => false,
Missing => true,
#[cfg(feature = "alloc")]
Multiple(list) => list.is_empty(),
}
}
}
pub struct Remit<'a, T>(Mode<'a, T>);
impl<T> Remit<'_, T> {
#[inline(always)]
pub fn value(&self, value: T) -> impl Future<Output=()> + '_ {
self.value_impl(value)
}
#[cfg(not(feature = "alloc"))]
fn value_impl(&self, value: T) -> impl Future<Output=()> + '_ {
self.0.push(value);
poll_fn(|_ctx|
if self.0.is_empty() {
Poll::Ready(())
} else {
Poll::Pending
}
)
}
#[cfg(feature = "alloc")]
fn value_impl(&self, value: T) -> impl Future<Output=()> + '_ {
if unsafe { self.strong() } {
self.0.push(value);
}
poll_fn(|_ctx|
if unsafe { self.strong() } && self.0.is_empty() {
Poll::Ready(())
} else {
Poll::Pending
}
)
}
#[cfg(feature = "alloc")]
unsafe fn strong(&self) -> bool {
if let &Remit(Mode::Boxed(ptr)) = self {
let inner_ptr = (*addr_of!((*ptr).ptr)).get();
(*addr_of!((*ptr).checker))(inner_ptr)
} else {
true
}
}
#[cfg(feature = "alloc")]
unsafe fn dropping(&mut self) {
if let &mut Remit(Mode::Boxed(ptr)) = self {
let inner_ptr = (*addr_of!((*ptr).ptr)).get();
(*addr_of!((*ptr).dropper))(inner_ptr)
}
}
}
#[cfg(feature = "alloc")]
impl<T> Drop for Remit<'_, T> {
fn drop(&mut self) {
unsafe { self.dropping() }
}
}