@@ -19,6 +19,36 @@ use stack;
1919use debug;
2020use arch:: { self , StackPointer } ;
2121
22+ // Wrapper to prevent the compiler from automatically dropping a value when it
23+ // goes out of scope. This is particularly useful when dealing with unwinding
24+ // since mem::forget won't be executed when unwinding.
25+ #[ allow( unions_with_drop_fields) ]
26+ union NoDrop < T > {
27+ inner : T ,
28+ }
29+
30+ // Try to pack a value into a usize if it fits, otherwise pass its address as a usize.
31+ unsafe fn encode_usize < T > ( val : & NoDrop < T > ) -> usize {
32+ if mem:: size_of :: < T > ( ) <= mem:: size_of :: < usize > ( ) &&
33+ mem:: align_of :: < T > ( ) <= mem:: align_of :: < usize > ( ) {
34+ let mut out = 0 ;
35+ ptr:: copy_nonoverlapping ( & val. inner , & mut out as * mut usize as * mut T , 1 ) ;
36+ out
37+ } else {
38+ & val. inner as * const T as usize
39+ }
40+ }
41+
42+ // Unpack a usize produced by encode_usize.
43+ unsafe fn decode_usize < T > ( val : usize ) -> T {
44+ if mem:: size_of :: < T > ( ) <= mem:: size_of :: < usize > ( ) &&
45+ mem:: align_of :: < T > ( ) <= mem:: align_of :: < usize > ( ) {
46+ ptr:: read ( & val as * const usize as * const T )
47+ } else {
48+ ptr:: read ( val as * const T )
49+ }
50+ }
51+
2252#[ derive( Debug , Clone , Copy ) ]
2353pub enum State {
2454 /// Generator can be resumed. This is the initial state.
@@ -114,10 +144,10 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
114144 where Input : Send , Output : Send , Stack : stack:: Stack ,
115145 F : FnOnce ( & Yielder < Input , Output > , Input ) {
116146 // Retrieve our environment from the callee and return control to it.
117- let f = ptr :: read ( env as * const F ) ;
147+ let f: F = decode_usize ( env) ;
118148 let ( data, stack_ptr) = arch:: swap ( 0 , stack_ptr) ;
119149 // See the second half of Yielder::suspend_bare.
120- let input = ptr :: read ( data as * const Input ) ;
150+ let input = decode_usize ( data) ;
121151 // Run the body of the generator.
122152 let yielder = Yielder :: new ( stack_ptr) ;
123153 f ( & yielder, input) ;
@@ -127,8 +157,8 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
127157 let stack_ptr = arch:: init ( & stack, generator_wrapper :: < Input , Output , Stack , F > ) ;
128158
129159 // Transfer environment to the callee.
130- let stack_ptr = arch :: swap_link ( & f as * const F as usize , stack_ptr , & stack ) . 1 ;
131- mem :: forget ( f ) ;
160+ let f2 = NoDrop { inner : f } ;
161+ let stack_ptr = arch :: swap_link ( encode_usize ( & f2 ) , stack_ptr , & stack ) . 1 ;
132162
133163 Generator {
134164 stack : stack,
@@ -151,13 +181,13 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
151181
152182 // Switch to the generator function, and retrieve the yielded value.
153183 unsafe {
154- let ( data_out, stack_ptr) = arch:: swap_link ( & input as * const Input as usize , stack_ptr, & self . stack ) ;
184+ let input2 = NoDrop { inner : input } ;
185+ let ( data_out, stack_ptr) = arch:: swap_link ( encode_usize ( & input2) , stack_ptr, & self . stack ) ;
155186 self . stack_ptr = stack_ptr;
156- mem:: forget ( input) ;
157187
158188 // If the generator function has finished, return None, otherwise return the
159189 // yielded value.
160- stack_ptr. map ( |_| ptr :: read ( data_out as * const Output ) )
190+ stack_ptr. map ( |_| decode_usize ( data_out) )
161191 }
162192 } )
163193 }
@@ -201,10 +231,10 @@ impl<Input, Output> Yielder<Input, Output>
201231 #[ inline( always) ]
202232 pub fn suspend ( & self , item : Output ) -> Input {
203233 unsafe {
204- let ( data , stack_ptr ) = arch :: swap ( & item as * const Output as usize , self . stack_ptr . get ( ) ) ;
205- mem :: forget ( item ) ;
234+ let item2 = NoDrop { inner : item } ;
235+ let ( data , stack_ptr ) = arch :: swap ( encode_usize ( & item2 ) , self . stack_ptr . get ( ) ) ;
206236 self . stack_ptr . set ( stack_ptr) ;
207- ptr :: read ( data as * const Input )
237+ decode_usize ( data)
208238 }
209239 }
210240}
0 commit comments