Skip to content

Instantly share code, notes, and snippets.

@Amanieu
Created September 7, 2016 18:55
Show Gist options
  • Save Amanieu/585bbf73377783b0ea807d43837f408b to your computer and use it in GitHub Desktop.
Save Amanieu/585bbf73377783b0ea807d43837f408b to your computer and use it in GitHub Desktop.
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