1- use std:: cell:: Cell ;
1+ //! This module provides a way to deal with self-referential data.
2+ //!
3+ //! The main idea is to allocate such data in a generator frame and then
4+ //! give access to it by executing user-provided closures inside that generator.
5+ //! The module provides a safe abstraction for the latter task.
6+ //!
7+ //! The interface consists of two exported macros meant to be used together:
8+ //! * `declare_box_region_type` wraps a generator inside a struct with `access`
9+ //! method which accepts closures.
10+ //! * `box_region_allow_access` is a helper which should be called inside
11+ //! a generator to actually execute those closures.
12+
213use std:: marker:: PhantomData ;
314use std:: ops:: { Generator , GeneratorState } ;
415use std:: pin:: Pin ;
@@ -14,24 +25,23 @@ impl AccessAction {
1425
1526#[ derive( Copy , Clone ) ]
1627pub enum Action {
28+ Initial ,
1729 Access ( AccessAction ) ,
1830 Complete ,
1931}
2032
21- thread_local ! ( pub static BOX_REGION_ARG : Cell <Action > = Cell :: new( Action :: Complete ) ) ;
22-
2333pub struct PinnedGenerator < I , A , R > {
24- generator : Pin < Box < dyn Generator < Yield = YieldType < I , A > , Return = R > > > ,
34+ generator : Pin < Box < dyn Generator < Action , Yield = YieldType < I , A > , Return = R > > > ,
2535}
2636
2737impl < I , A , R > PinnedGenerator < I , A , R > {
28- pub fn new < T : Generator < Yield = YieldType < I , A > , Return = R > + ' static > (
38+ pub fn new < T : Generator < Action , Yield = YieldType < I , A > , Return = R > + ' static > (
2939 generator : T ,
3040 ) -> ( I , Self ) {
3141 let mut result = PinnedGenerator { generator : Box :: pin ( generator) } ;
3242
3343 // Run it to the first yield to set it up
34- let init = match Pin :: new ( & mut result. generator ) . resume ( ( ) ) {
44+ let init = match Pin :: new ( & mut result. generator ) . resume ( Action :: Initial ) {
3545 GeneratorState :: Yielded ( YieldType :: Initial ( y) ) => y,
3646 _ => panic ! ( ) ,
3747 } ;
@@ -40,21 +50,17 @@ impl<I, A, R> PinnedGenerator<I, A, R> {
4050 }
4151
4252 pub unsafe fn access ( & mut self , closure : * mut dyn FnMut ( ) ) {
43- BOX_REGION_ARG . with ( |i| {
44- i. set ( Action :: Access ( AccessAction ( closure) ) ) ;
45- } ) ;
46-
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+ // Call the generator, which in turn will call the closure
54+ if let GeneratorState :: Complete ( _) =
55+ Pin :: new ( & mut self . generator ) . resume ( Action :: Access ( AccessAction ( closure) ) )
56+ {
4957 panic ! ( )
5058 }
5159 }
5260
5361 pub fn complete ( & mut self ) -> R {
5462 // Tell the generator we want it to complete, consuming it and yielding a result
55- BOX_REGION_ARG . with ( |i| i. set ( Action :: Complete ) ) ;
56-
57- let result = Pin :: new ( & mut self . generator ) . resume ( ( ) ) ;
63+ let result = Pin :: new ( & mut self . generator ) . resume ( Action :: Complete ) ;
5864 if let GeneratorState :: Complete ( r) = result { r } else { panic ! ( ) }
5965 }
6066}
@@ -89,7 +95,7 @@ macro_rules! declare_box_region_type {
8995 >) ;
9096
9197 impl $name {
92- fn new<T : :: std:: ops:: Generator <Yield = $yield_type, Return = $retc> + ' static >(
98+ fn new<T : :: std:: ops:: Generator <$crate :: box_region :: Action , Yield = $yield_type, Return = $retc> + ' static >(
9399 generator: T
94100 ) -> ( $reti, Self ) {
95101 let ( initial, pinned) = $crate:: box_region:: PinnedGenerator :: new( generator) ;
@@ -98,7 +104,7 @@ macro_rules! declare_box_region_type {
98104
99105 $v fn access<F : for <$( $lifetimes) * > FnOnce ( $( $args, ) * ) -> R , R >( & mut self , f: F ) -> R {
100106 // 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
107+ // so we can pass it in to the generator
102108 let mut r = None ;
103109 let mut f = Some ( f) ;
104110 let mut_f: & mut dyn for <$( $lifetimes) * > FnMut ( ( $( $args, ) * ) ) =
@@ -140,9 +146,9 @@ macro_rules! declare_box_region_type {
140146#[ macro_export]
141147#[ allow_internal_unstable( fn_traits) ]
142148macro_rules! box_region_allow_access {
143- ( for ( $( $lifetimes: tt) * ) , ( $( $args: ty) ,* ) , ( $( $exprs: expr) ,* ) ) => {
149+ ( for ( $( $lifetimes: tt) * ) , ( $( $args: ty) ,* ) , ( $( $exprs: expr) ,* ) , $action : ident ) => {
144150 loop {
145- match $crate :: box_region :: BOX_REGION_ARG . with ( |i| i . get ( ) ) {
151+ match $action {
146152 $crate:: box_region:: Action :: Access ( accessor) => {
147153 let accessor: & mut dyn for <$( $lifetimes) * > FnMut ( $( $args) ,* ) = unsafe {
148154 :: std:: mem:: transmute( accessor. get( ) )
@@ -152,10 +158,11 @@ macro_rules! box_region_allow_access {
152158 let marker = $crate:: box_region:: Marker :: <
153159 for <$( $lifetimes) * > fn ( ( $( $args, ) * ) )
154160 >:: new( ) ;
155- yield $crate:: box_region:: YieldType :: Accessor ( marker)
161+ $action = yield $crate:: box_region:: YieldType :: Accessor ( marker) ;
156162 } ;
157163 }
158164 $crate:: box_region:: Action :: Complete => break ,
165+ $crate:: box_region:: Action :: Initial => panic!( "unexpected box_region action: Initial" ) ,
159166 }
160167 }
161168 }
0 commit comments