Created
September 7, 2016 18:55
-
-
Save Amanieu/585bbf73377783b0ea807d43837f408b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/generator.rs b/src/generator.rs | |
index 6870c29..9065e38 100644 | |
--- a/src/generator.rs | |
+++ b/src/generator.rs | |
@@ -88,6 +88,32 @@ pub struct Generator<Input: Send, Output: Send, Stack: stack::Stack> { | |
phantom: (PhantomData<*const Input>, PhantomData<*const Output>) | |
} | |
+unsafe fn encode<T>(val: &T) -> usize { | |
+ if mem::size_of::<T>() <= mem::size_of::<usize>() && | |
+ mem::align_of::<T>() <= mem::align_of::<usize>() { | |
+ let mut out = mem::uninitialized(); | |
+ ptr::copy_nonoverlapping(val as *const T as *const u8, | |
+ &mut out as *mut usize as *mut u8, | |
+ mem::size_of::<T>()); | |
+ out | |
+ } else { | |
+ val as *const T as usize | |
+ } | |
+} | |
+ | |
+unsafe fn decode<T>(val: usize) -> T { | |
+ if mem::size_of::<T>() <= mem::size_of::<usize>() && | |
+ mem::align_of::<T>() <= mem::align_of::<usize>() { | |
+ let mut out = mem::uninitialized(); | |
+ ptr::copy_nonoverlapping(&val as *const usize as *const u8, | |
+ &mut out as *mut T as *mut u8, | |
+ mem::size_of::<T>()); | |
+ out | |
+ } else { | |
+ ptr::read(val as *const T) | |
+ } | |
+} | |
+ | |
impl<Input, Output, Stack> Generator<Input, Output, Stack> | |
where Input: Send, Output: Send, Stack: stack::Stack { | |
/// Creates a new generator. | |
@@ -112,10 +138,10 @@ impl<Input, Output, Stack> Generator<Input, Output, Stack> | |
where Input: Send, Output: Send, Stack: stack::Stack, | |
F: FnOnce(&mut Yielder<Input, Output>, Input) { | |
// Retrieve our environment from the callee and return control to it. | |
- let f = ptr::read(env as *const F); | |
+ let f = decode::<F>(env); | |
let (data, stack_ptr) = arch::swap(0, stack_ptr, None); | |
// See the second half of Yielder::suspend_bare. | |
- let input = ptr::read(data as *const Input); | |
+ let input = decode::<Input>(data); | |
// Run the body of the generator. | |
let mut yielder = Yielder::new(stack_ptr); | |
f(&mut yielder, input); | |
@@ -127,7 +153,7 @@ impl<Input, Output, Stack> Generator<Input, Output, Stack> | |
let stack_ptr = arch::init(&stack, generator_wrapper::<Input, Output, Stack, F>); | |
// Transfer environment to the callee. | |
- let stack_ptr = arch::swap(&f as *const F as usize, stack_ptr, Some(&stack)).1; | |
+ let stack_ptr = arch::swap(encode(&f), stack_ptr, Some(&stack)).1; | |
mem::forget(f); | |
Generator { | |
@@ -152,10 +178,10 @@ impl<Input, Output, Stack> Generator<Input, Output, Stack> | |
// Switch to the generator function, and retrieve the yielded value. | |
let val = unsafe { | |
- let (data_out, stack_ptr) = arch::swap(&input as *const Input as usize, self.stack_ptr, Some(&self.stack)); | |
+ let (data_out, stack_ptr) = arch::swap(encode(&input), self.stack_ptr, Some(&self.stack)); | |
self.stack_ptr = stack_ptr; | |
mem::forget(input); | |
- ptr::read(data_out as *const Option<Output>) | |
+ decode::<Option<Output>>(data_out) | |
}; | |
// Unless the generator function has returned, it can be switched to again, so | |
@@ -203,10 +229,10 @@ impl<Input, Output> Yielder<Input, Output> | |
#[inline(always)] | |
fn suspend_bare(&self, val: Option<Output>) -> Input { | |
unsafe { | |
- let (data, stack_ptr) = arch::swap(&val as *const Option<Output> as usize, self.stack_ptr.get(), None); | |
+ let (data, stack_ptr) = arch::swap(encode(&val), self.stack_ptr.get(), None); | |
self.stack_ptr.set(stack_ptr); | |
mem::forget(val); | |
- ptr::read(data as *const Input) | |
+ decode::<Input>(data) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment