use_prelude!();
mod internals { use super::*;
#[allow(bad_style)]
pub
struct YieldSlot<'yield_slot, Item : 'yield_slot> {
pub(in super)
item_slot: Pin<&'yield_slot ItemSlot<Item>>,
}
} use internals::YieldSlot;
#[doc(hidden, inline)]
pub use internals::YieldSlot as __Internals_YieldSlot_DoNotUse__;
impl<Item> Drop for YieldSlot<'_, Item> {
fn drop (self: &'_ mut Self)
{
self.item_slot.drop_flag.set(());
}
}
struct ItemSlot<Item> {
value: CellOption<Item>,
drop_flag: CellOption<()>,
}
impl<'yield_slot, Item : 'yield_slot> YieldSlot<'yield_slot, Item> {
#[inline]
fn new (item_slot: Pin<&'yield_slot ItemSlot<Item>>)
-> Self
{
Self { item_slot }
}
#[doc(hidden)]
pub
fn put (self: &'_ Self, value: Item)
-> impl Future<Output = ()> + '_
{
let prev: Option<Item> = self.item_slot.value.set(value);
debug_assert!(prev.is_none(), "slot was empty");
return WaitForClear { yield_slot: self };
struct WaitForClear<'yield_slot, Item : 'yield_slot> {
yield_slot: &'yield_slot YieldSlot<'yield_slot, Item>,
}
impl<'yield_slot, Item> Future for WaitForClear<'yield_slot, Item> {
type Output = ();
fn poll (self: Pin<&'_ mut Self>, _: &'_ mut Context<'_>)
-> Poll<()>
{
if self.yield_slot.item_slot.value.is_some() {
Poll::Pending
} else {
Poll::Ready(())
}
}
}
}
}
pub
struct GeneratorFn<Item, F : Future> {
item_slot: ItemSlot<Item>,
future: Option<F>,
}
impl<Item, F : Future> Drop for GeneratorFn<Item, F> {
fn drop (self: &'_ mut Self)
{
drop(self.future.take());
if self.item_slot.drop_flag.is_none() {
eprintln!(concat!(
"`::next_gen` fatal runtime error: ",
"a `YieldSlot` was about to dangle!",
"\n",
"\n",
"This is only possible if the internals of `::next_gen` were ",
"(ab)used directly, ",
"by making a `YieldSlot` escape the `#[generator] fn`.",
"\n",
"Since this could lead to memory unsafety, ",
"the program will now abort.",
));
::std::process::abort();
}
}
}
struct GeneratorPinnedFields<'pin, Item : 'pin, F : Future + 'pin> {
item_slot: Pin<&'pin ItemSlot<Item>>,
future: Pin<&'pin mut F>,
}
impl<Item, F : Future> GeneratorFn<Item, F> {
fn project (self: Pin<&'_ mut Self>) -> GeneratorPinnedFields<'_, Item, F>
{
unsafe {
let this = self.get_unchecked_mut();
GeneratorPinnedFields {
item_slot: Pin::new_unchecked(&this.item_slot),
future: Pin::new_unchecked(
this.future
.as_mut()
.expect("You must init a GeneratorFn before using it!")
),
}
}
}
pub
fn empty ()
-> Self
{
Self {
item_slot: ItemSlot {
value: CellOption::None,
drop_flag: CellOption::None,
},
future: None,
}
}
pub
fn init<'pin, 'yield_slot, Args> (
self: Pin<&'pin mut Self>,
factory: impl FnOnce(YieldSlot<'yield_slot, Item>, Args) -> F,
args: Args,
)
where
Item : 'yield_slot,
{
assert!(self.future.is_none(),
"GeneratorFn cannot be initialized multiple times!",
);
unsafe {
let this = self.get_unchecked_mut();
let yield_slot =
YieldSlot::new(Pin::new_unchecked(
::core::mem::transmute::<
&'pin ItemSlot<Item>,
&'yield_slot ItemSlot<Item>,
>(
&this.item_slot
)
))
;
this.future = Some(factory(yield_slot, args));
}
}
#[inline]
pub
fn resume (self: Pin<&'_ mut Self>)
-> GeneratorState<Item, F::Output>
{
<Self as Generator>::resume(self)
}
}
pub
trait Generator {
type Yield;
type Return;
fn resume (self: Pin<&'_ mut Self>)
-> GeneratorState<Self::Yield, Self::Return>
;
}
impl<Item, F : Future> Generator for GeneratorFn<Item, F> {
type Yield = Item;
type Return = F::Output;
fn resume (self: Pin<&'_ mut Self>)
-> GeneratorState<Item, F::Output>
{
let this = self.project(); create_context!(cx);
match this.future.poll(&mut cx) {
| Poll::Pending => {
let value =
this.item_slot
.value
.take()
.expect("Missing item in yield_slot!")
;
GeneratorState::Yield(value)
},
| Poll::Ready(value) => {
GeneratorState::Return(value)
}
}
}
}
#[derive(
Debug,
Clone, Copy,
PartialEq, Eq,
PartialOrd, Ord,
Hash
)]
pub
enum GeneratorState<Yield, Return = ()> {
Yield(Yield),
Return(Return),
}
impl<'a, G : ?Sized + 'a> Generator for Pin<&'a mut G>
where
G : Generator,
{
type Yield = G::Yield;
type Return = G::Return;
#[inline]
fn resume (mut self: Pin<&'_ mut Pin<&'a mut G>>)
-> GeneratorState<Self::Yield, Self::Return>
{
G::resume(
Pin::<&mut G>::as_mut(&mut *self)
)
}
}
impl<'a, G : ?Sized + 'a> Generator for &'a mut G
where
G : Generator + Unpin,
{
type Yield = G::Yield;
type Return = G::Return;
#[inline]
fn resume (mut self: Pin<&'_ mut &'a mut G>)
-> GeneratorState<Self::Yield, Self::Return>
{
G::resume(
Pin::<&mut G>::new(&mut *self)
)
}
}