2 use std
::marker
::PhantomData
;
3 use std
::ops
::{Generator, GeneratorState}
;
7 pub struct AccessAction(*mut dyn FnMut());
10 pub fn get(self) -> *mut dyn FnMut() {
15 #[derive(Copy, Clone)]
21 thread_local
!(pub static BOX_REGION_ARG
: Cell
<Action
> = Cell
::new(Action
::Complete
));
23 pub struct PinnedGenerator
<I
, A
, R
> {
24 generator
: Pin
<Box
<dyn Generator
<Yield
= YieldType
<I
, A
>, Return
= R
>>>,
27 impl<I
, A
, R
> PinnedGenerator
<I
, A
, R
> {
28 pub fn new
<T
: Generator
<Yield
= YieldType
<I
, A
>, Return
= R
> + '
static>(
31 let mut result
= PinnedGenerator { generator: Box::pin(generator) }
;
33 // Run it to the first yield to set it up
34 let init
= match Pin
::new(&mut result
.generator
).resume(()) {
35 GeneratorState
::Yielded(YieldType
::Initial(y
)) => y
,
42 pub unsafe fn access(&mut self, closure
: *mut dyn FnMut()) {
43 BOX_REGION_ARG
.with(|i
| {
44 i
.set(Action
::Access(AccessAction(closure
)));
47 // Call the generator, which in turn will call the closure in BOX_REGION_ARG
48 if let GeneratorState
::Complete(_
) = Pin
::new(&mut self.generator
).resume(()) {
53 pub fn complete(&mut self) -> R
{
54 // Tell the generator we want it to complete, consuming it and yielding a result
55 BOX_REGION_ARG
.with(|i
| i
.set(Action
::Complete
));
57 let result
= Pin
::new(&mut self.generator
).resume(());
58 if let GeneratorState
::Complete(r
) = result { r }
else { panic!() }
63 pub struct Marker
<T
>(PhantomData
<T
>);
66 pub unsafe fn new() -> Self {
71 pub enum YieldType
<I
, A
> {
77 #[allow_internal_unstable(fn_traits)]
78 macro_rules
! declare_box_region_type
{
82 for($
($lifetimes
:tt
)*),
83 ($
($args
:ty
),*) -> ($reti
:ty
, $retc
:ty
)
85 $v
struct $
name($
crate::box_region
::PinnedGenerator
<
87 for<$
($lifetimes
)*> fn(($
($args
,)*)),
92 fn new
<T
: ::std
::ops
::Generator
<Yield
= $yield_type
, Return
= $retc
> + '
static>(
95 let (initial
, pinned
) = $
crate::box_region
::PinnedGenerator
::new(generator
);
96 (initial
, $
name(pinned
))
99 $v
fn access
<F
: for<$
($lifetimes
)*> FnOnce($
($args
,)*) -> R
, R
>(&mut self, f
: F
) -> R
{
100 // Turn the FnOnce closure into *mut dyn FnMut()
101 // so we can pass it in to the generator using the BOX_REGION_ARG thread local
104 let mut_f
: &mut dyn for<$
($lifetimes
)*> FnMut(($
($args
,)*)) =
106 let f
= f
.take().unwrap();
107 r
= Some(FnOnce
::call_once(f
, args
));
109 let mut_f
= mut_f
as *mut dyn for<$
($lifetimes
)*> FnMut(($
($args
,)*));
111 // Get the generator to call our closure
113 self.0.access(::std
::mem
::transmute(mut_f
));
120 $v
fn complete(mut self) -> $retc
{
124 fn initial_yield(value
: $reti
) -> $yield_type
{
125 $
crate::box_region
::YieldType
::Initial(value
)
130 ($v
:vis $name
: ident
, for($
($lifetimes
:tt
)*), ($
($args
:ty
),*) -> ($reti
:ty
, $retc
:ty
)) => {
131 declare_box_region_type
!(
133 $
crate::box_region
::YieldType
<$reti
, for<$
($lifetimes
)*> fn(($
($args
,)*))>,
135 ($
($args
),*) -> ($reti
, $retc
)
141 #[allow_internal_unstable(fn_traits)]
142 macro_rules
! box_region_allow_access
{
143 (for($
($lifetimes
:tt
)*), ($
($args
:ty
),*), ($
($exprs
:expr
),*) ) => {
145 match $
crate::box_region
::BOX_REGION_ARG
.with(|i
| i
.get()) {
146 $
crate::box_region
::Action
::Access(accessor
) => {
147 let accessor
: &mut dyn for<$
($lifetimes
)*> FnMut($
($args
),*) = unsafe {
148 ::std
::mem
::transmute(accessor
.get())
150 (*accessor
)(($
($exprs
),*));
152 let marker
= $
crate::box_region
::Marker
::<
153 for<$
($lifetimes
)*> fn(($
($args
,)*))
155 yield $
crate::box_region
::YieldType
::Accessor(marker
)
158 $
crate::box_region
::Action
::Complete
=> break,