diff --git a/core/block.rs b/core/block.rs index 9988a5fb2..0b81e4977 100644 --- a/core/block.rs +++ b/core/block.rs @@ -45,6 +45,7 @@ to be copied once, and we can enforce this in Rust, but if Objective-C code were to copy it twice we could have a double free. */ +use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr; @@ -69,7 +70,8 @@ macro_rules! block_args_impl { impl<$($t),*> BlockArguments for ($($t,)*) { fn call_block(self, block: &mut Block) -> R { let invoke: unsafe extern fn(*mut Block $(, $t)*) -> R = unsafe { - mem::transmute(block.invoke) + let base = &*(block as *mut _ as *mut BlockBase); + mem::transmute(base.invoke) }; let ($($a,)*) = self; unsafe { @@ -94,16 +96,21 @@ block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); -/// An Objective-C block that takes arguments of `A` when called and -/// returns a value of `R`. #[repr(C)] -pub struct Block { +struct BlockBase { isa: *const Class, flags: c_int, _reserved: c_int, invoke: unsafe extern fn(*mut Block, ...) -> R, } +/// An Objective-C block that takes arguments of `A` when called and +/// returns a value of `R`. +#[repr(C)] +pub struct Block { + _base: PhantomData>, +} + // TODO: impl FnMut when it's possible impl Block where A: BlockArguments { /// Call self with the given arguments. @@ -172,7 +179,7 @@ concrete_block_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, /// constructed on the stack. #[repr(C)] pub struct ConcreteBlock { - base: Block, + base: BlockBase, descriptor: Box>>, closure: F, } @@ -194,7 +201,7 @@ impl ConcreteBlock { unsafe fn with_invoke(invoke: unsafe extern fn(*mut Self, ...) -> R, closure: F) -> Self { ConcreteBlock { - base: Block { + base: BlockBase { isa: &_NSConcreteStackBlock, // 1 << 25 = BLOCK_HAS_COPY_DISPOSE flags: 1 << 25, @@ -212,7 +219,7 @@ impl ConcreteBlock where F: 'static { pub fn copy(self) -> Id> { unsafe { // The copy method is declared as returning an object pointer. - let block: *mut Object = msg_send![&self.base, copy]; + let block: *mut Object = msg_send![&*self, copy]; let block = block as *mut Block; // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block @@ -226,7 +233,7 @@ impl ConcreteBlock where F: 'static { impl Clone for ConcreteBlock where F: Clone { fn clone(&self) -> Self { unsafe { - ConcreteBlock::with_invoke(mem::transmute(self.invoke), + ConcreteBlock::with_invoke(mem::transmute(self.base.invoke), self.closure.clone()) } } @@ -236,13 +243,13 @@ impl Deref for ConcreteBlock { type Target = Block; fn deref(&self) -> &Block { - &self.base + unsafe { &*(&self.base as *const _ as *const Block) } } } impl DerefMut for ConcreteBlock { fn deref_mut(&mut self) -> &mut Block { - &mut self.base + unsafe { &mut *(&mut self.base as *mut _ as *mut Block) } } }