Use core::mem::ManuallyDrop instead of implementing our own NoDrop

This commit is contained in:
edef 2017-12-08 12:42:17 -05:00
parent 5849a2d330
commit 17c41ce777

View File

@ -14,6 +14,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use core::{ptr, mem}; use core::{ptr, mem};
use core::cell::Cell; use core::cell::Cell;
use core::mem::ManuallyDrop;
use stack; use stack;
use debug; use debug;
@ -84,26 +85,12 @@ pub enum State {
#[derive(Debug)] #[derive(Debug)]
pub struct Generator<'a, Input: 'a, Output: 'a, Stack: stack::Stack> { pub struct Generator<'a, Input: 'a, Output: 'a, Stack: stack::Stack> {
state: State, state: State,
stack: NoDrop<Stack>, stack: ManuallyDrop<Stack>,
stack_id: NoDrop<debug::StackId>, stack_id: ManuallyDrop<debug::StackId>,
stack_ptr: arch::StackPointer, stack_ptr: arch::StackPointer,
phantom: PhantomData<(&'a (), *mut Input, *const Output)> phantom: PhantomData<(&'a (), *mut Input, *const Output)>
} }
#[allow(unions_with_drop_fields)]
union NoDrop<T> {
inner: T
}
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for NoDrop<T> {
fn fmt(&self, w: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
unsafe {
// this is safe because we never invoke formatting on the empty variant
self.inner.fmt(w)
}
}
}
impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack> impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
where Input: 'a, Output: 'a, Stack: stack::Stack { where Input: 'a, Output: 'a, Stack: stack::Stack {
/// Creates a new generator. /// Creates a new generator.
@ -147,8 +134,8 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
Generator { Generator {
state: State::Runnable, state: State::Runnable,
stack: NoDrop { inner: stack }, stack: ManuallyDrop::new(stack),
stack_id: NoDrop { inner: stack_id }, stack_id: ManuallyDrop::new(stack_id),
stack_ptr: stack_ptr, stack_ptr: stack_ptr,
phantom: PhantomData phantom: PhantomData
} }
@ -167,7 +154,7 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
// Switch to the generator function, and retrieve the yielded value. // Switch to the generator function, and retrieve the yielded value.
let val = unsafe { let val = unsafe {
let (data_out, stack_ptr) = arch::swap(&input as *const Input as usize, self.stack_ptr, Some(&self.stack.inner)); let (data_out, stack_ptr) = arch::swap(&input as *const Input as usize, self.stack_ptr, Some(&*self.stack));
self.stack_ptr = stack_ptr; self.stack_ptr = stack_ptr;
mem::forget(input); mem::forget(input);
ptr::read(data_out as *const Option<Output>) ptr::read(data_out as *const Option<Output>)
@ -203,8 +190,8 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
/// Extracts the stack from a generator without checking if the generator function has returned. /// Extracts the stack from a generator without checking if the generator function has returned.
/// This will leave any pointers into the generator stack dangling, and won't run destructors. /// This will leave any pointers into the generator stack dangling, and won't run destructors.
pub unsafe fn unsafe_unwrap(mut self) -> Stack { pub unsafe fn unsafe_unwrap(mut self) -> Stack {
ptr::drop_in_place(&mut self.stack_id.inner); ManuallyDrop::drop(&mut self.stack_id);
let stack = ptr::read(&mut self.stack.inner); let stack = ptr::read(&mut *self.stack);
mem::forget(self); mem::forget(self);
stack stack
} }
@ -214,10 +201,10 @@ impl<'a, Input, Output, Stack> Drop for Generator<'a, Input, Output, Stack>
where Input: 'a, Output: 'a, Stack: stack::Stack { where Input: 'a, Output: 'a, Stack: stack::Stack {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
ptr::drop_in_place(&mut self.stack_id.inner); ManuallyDrop::drop(&mut self.stack_id);
match self.state { match self.state {
State::Runnable => panic!("dropped unfinished Generator"), State::Runnable => panic!("dropped unfinished Generator"),
State::Unavailable => ptr::drop_in_place(&mut self.stack.inner) State::Unavailable => ManuallyDrop::drop(&mut self.stack)
} }
} }
} }