/// Types that may be used as the arguments to an Objective-C block. pubtrait BlockArguments: Sized { /// Calls the given `Block` with self as the arguments. /// /// Unsafe because `block` must point to a valid `Block` and this invokes /// foreign code whose safety the compiler cannot verify. unsafefn call_block<R>(self, block: *mut Block<Self, R>) -> R;
}
macro_rules! block_args_impl {
($($a:ident : $t:ident),*) => ( impl<$($t),*> BlockArguments for ($($t,)*) { unsafefn call_block<R>(self, block: *mut Block<Self, R>) -> R { let invoke: unsafeexternfn(*mut Block<Self, R> $(, $t)*) -> R = { let base = block as *mut BlockBase<Self, R>;
mem::transmute((*base).invoke)
}; let ($($a,)*) = self;
invoke(block $(, $a)*)
}
}
);
}
block_args_impl!();
block_args_impl!(a: A);
block_args_impl!(a: A, b: B);
block_args_impl!(a: A, b: B, c: C);
block_args_impl!(a: A, b: B, c: C, d: D);
block_args_impl!(a: A, b: B, c: C, d: D, e: E);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
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)] pubstruct Block<A, R> {
_base: PhantomData<BlockBase<A, R>>,
}
impl<A: BlockArguments, R> Block<A, R> where A: BlockArguments { /// Call self with the given arguments. /// /// Unsafe because this invokes foreign code that the caller must verify /// doesn't violate any of Rust's safety rules. For example, if this block /// is shared with multiple references, the caller must ensure that calling /// it will not cause a data race. pubunsafefn call(&self, args: A) -> R {
args.call_block(selfas *const _ as *mut _)
}
}
impl<A, R> RcBlock<A, R> { /// Construct an `RcBlock` for the given block without copying it. /// The caller must ensure the block has a +1 reference count. /// /// Unsafe because `ptr` must point to a valid `Block` and must have a +1 /// reference count or it will be overreleased when the `RcBlock` is /// dropped. pubunsafefn new(ptr: *mut Block<A, R>) -> Self {
RcBlock { ptr: ptr }
}
/// Constructs an `RcBlock` by copying the given block. /// /// Unsafe because `ptr` must point to a valid `Block`. pubunsafefn copy(ptr: *mut Block<A, R>) -> Self { let ptr = _Block_copy(ptr as *const c_void) as *mut Block<A, R>;
RcBlock { ptr: ptr }
}
}
impl<A, R> Drop for RcBlock<A, R> { fn drop(&mutself) { unsafe {
_Block_release(self.ptr as *const c_void);
}
}
}
/// Types that may be converted into a `ConcreteBlock`. pubtrait IntoConcreteBlock<A>: Sized where A: BlockArguments { /// The return type of the resulting `ConcreteBlock`. type Ret;
/// Consumes self to create a `ConcreteBlock`. fn into_concrete_block(self) -> ConcreteBlock<A, Self::Ret, Self>;
}
macro_rules! concrete_block_impl {
($f:ident) => (
concrete_block_impl!($f,);
);
($f:ident, $($a:ident : $t:ident),*) => ( impl<$($t,)* R, X> IntoConcreteBlock<($($t,)*)> for X where X: Fn($($t,)*) -> R { type Ret = R;
fn into_concrete_block(self) -> ConcreteBlock<($($t,)*), R, X> { unsafeexternfn $f<$($t,)* R, X>(
block_ptr: *mut ConcreteBlock<($($t,)*), R, X>
$(, $a: $t)*) -> R where X: Fn($($t,)*) -> R { let block = &*block_ptr;
(block.closure)($($a),*)
}
concrete_block_impl!(concrete_block_invoke_args0);
concrete_block_impl!(concrete_block_invoke_args1, a: A);
concrete_block_impl!(concrete_block_invoke_args2, a: A, b: B);
concrete_block_impl!(concrete_block_invoke_args3, a: A, b: B, c: C);
concrete_block_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D);
concrete_block_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E);
concrete_block_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F);
concrete_block_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G);
concrete_block_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
concrete_block_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
concrete_block_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
concrete_block_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
concrete_block_impl!(concrete_block_invoke_args12, 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 whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] pubstruct ConcreteBlock<A, R, F> {
base: BlockBase<A, R>,
descriptor: Box<BlockDescriptor<ConcreteBlock<A, R, F>>>,
closure: F,
}
impl<A, R, F> ConcreteBlock<A, R, F> where A: BlockArguments, F: IntoConcreteBlock<A, Ret=R> { /// Constructs a `ConcreteBlock` with the given closure. /// When the block is called, it will return the value that results from /// calling the closure. pubfn new(closure: F) -> Self {
closure.into_concrete_block()
}
}
impl<A, R, F> ConcreteBlock<A, R, F> { /// Constructs a `ConcreteBlock` with the given invoke function and closure. /// Unsafe because the caller must ensure the invoke function takes the /// correct arguments. unsafefn with_invoke(invoke: unsafeexternfn(*mutSelf, ...) -> R,
closure: F) -> Self {
ConcreteBlock {
base: BlockBase {
isa: &_NSConcreteStackBlock, // 1 << 25 = BLOCK_HAS_COPY_DISPOSE
flags: 1 << 25,
_reserved: 0,
invoke: mem::transmute(invoke),
},
descriptor: Box::new(BlockDescriptor::new()),
closure: closure,
}
}
}
impl<A, R, F> ConcreteBlock<A, R, F> where F: 'static { /// Copy self onto the heap as an `RcBlock`. pubfn copy(self) -> RcBlock<A, R> { unsafe { letmut block = self; let copied = RcBlock::copy(&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 // because the heap block will drop in our dispose helper.
mem::forget(block);
copied
}
}
}
#[test] fn test_create_block() { let block = ConcreteBlock::new(|| 13); let result = invoke_int_block(&block);
assert!(result == 13);
}
#[test] fn test_create_block_args() { let block = ConcreteBlock::new(|a: i32| a + 5); let result = invoke_add_block(&block, 6);
assert!(result == 11);
}
#[test] fn test_concrete_block_copy() { let s = "Hello!".to_string(); let expected_len = s.len() as i32; let block = ConcreteBlock::new(move || s.len() as i32);
assert!(invoke_int_block(&block) == expected_len);
let copied = block.copy();
assert!(invoke_int_block(&copied) == expected_len);
}
#[test] fn test_concrete_block_stack_copy() { fn make_block() -> RcBlock<(), i32> { let x = 7; let block = ConcreteBlock::new(move || x);
block.copy()
}
let block = make_block();
assert!(invoke_int_block(&block) == 7);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.