Skip to content

Commit 2d4266d

Browse files
committed
Added a BlockBase struct so Block is 0-sized.
Fixes SSheldon#8.
1 parent ee154d7 commit 2d4266d

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

src/lib.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ to be copied once, and we can enforce this in Rust, but if Objective-C code
4545
were to copy it twice we could have a double free.
4646
*/
4747

48+
use std::marker::PhantomData;
4849
use std::mem;
4950
use std::ops::{Deref, DerefMut};
5051
use std::ptr;
@@ -69,7 +70,8 @@ macro_rules! block_args_impl {
6970
impl<$($t),*> BlockArguments for ($($t,)*) {
7071
fn call_block<R>(self, block: &mut Block<Self, R>) -> R {
7172
let invoke: unsafe extern fn(*mut Block<Self, R> $(, $t)*) -> R = unsafe {
72-
mem::transmute(block.invoke)
73+
let base = &*(block as *mut _ as *mut BlockBase<Self, R>);
74+
mem::transmute(base.invoke)
7375
};
7476
let ($($a,)*) = self;
7577
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);
9496
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);
9597
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);
9698

97-
/// An Objective-C block that takes arguments of `A` when called and
98-
/// returns a value of `R`.
9999
#[repr(C)]
100-
pub struct Block<A, R> {
100+
struct BlockBase<A, R> {
101101
isa: *const Class,
102102
flags: c_int,
103103
_reserved: c_int,
104104
invoke: unsafe extern fn(*mut Block<A, R>, ...) -> R,
105105
}
106106

107+
/// An Objective-C block that takes arguments of `A` when called and
108+
/// returns a value of `R`.
109+
#[repr(C)]
110+
pub struct Block<A, R> {
111+
_base: PhantomData<BlockBase<A, R>>,
112+
}
113+
107114
// TODO: impl FnMut when it's possible
108115
impl<A: BlockArguments, R> Block<A, R> where A: BlockArguments {
109116
/// 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,
172179
/// constructed on the stack.
173180
#[repr(C)]
174181
pub struct ConcreteBlock<A, R, F> {
175-
base: Block<A, R>,
182+
base: BlockBase<A, R>,
176183
descriptor: Box<BlockDescriptor<ConcreteBlock<A, R, F>>>,
177184
closure: F,
178185
}
@@ -194,7 +201,7 @@ impl<A, R, F> ConcreteBlock<A, R, F> {
194201
unsafe fn with_invoke(invoke: unsafe extern fn(*mut Self, ...) -> R,
195202
closure: F) -> Self {
196203
ConcreteBlock {
197-
base: Block {
204+
base: BlockBase {
198205
isa: &_NSConcreteStackBlock,
199206
// 1 << 25 = BLOCK_HAS_COPY_DISPOSE
200207
flags: 1 << 25,
@@ -212,7 +219,7 @@ impl<A, R, F> ConcreteBlock<A, R, F> where F: 'static {
212219
pub fn copy(self) -> Id<Block<A, R>> {
213220
unsafe {
214221
// The copy method is declared as returning an object pointer.
215-
let block: *mut Object = msg_send![&self.base, copy];
222+
let block: *mut Object = msg_send![&*self, copy];
216223
let block = block as *mut Block<A, R>;
217224
// At this point, our copy helper has been run so the block will
218225
// be moved to the heap and we can forget the original block
@@ -226,7 +233,7 @@ impl<A, R, F> ConcreteBlock<A, R, F> where F: 'static {
226233
impl<A, R, F> Clone for ConcreteBlock<A, R, F> where F: Clone {
227234
fn clone(&self) -> Self {
228235
unsafe {
229-
ConcreteBlock::with_invoke(mem::transmute(self.invoke),
236+
ConcreteBlock::with_invoke(mem::transmute(self.base.invoke),
230237
self.closure.clone())
231238
}
232239
}
@@ -236,13 +243,13 @@ impl<A, R, F> Deref for ConcreteBlock<A, R, F> {
236243
type Target = Block<A, R>;
237244

238245
fn deref(&self) -> &Block<A, R> {
239-
&self.base
246+
unsafe { &*(&self.base as *const _ as *const Block<A, R>) }
240247
}
241248
}
242249

243250
impl<A, R, F> DerefMut for ConcreteBlock<A, R, F> {
244251
fn deref_mut(&mut self) -> &mut Block<A, R> {
245-
&mut self.base
252+
unsafe { &mut *(&mut self.base as *mut _ as *mut Block<A, R>) }
246253
}
247254
}
248255

0 commit comments

Comments
 (0)