9 releases
0.2.0-alpha.7 | Dec 24, 2022 |
---|---|
0.2.0-alpha.6 | Aug 28, 2022 |
0.2.0-alpha.5 | Jul 19, 2022 |
0.2.0-alpha.4 | Jun 13, 2022 |
0.1.6 | Nov 19, 2021 |
#99 in macOS and iOS APIs
8,112 downloads per month
Used in icrate
34KB
740 lines
block2
Apple's C language extension of blocks in Rust.
This crate provides functionality for interracting with C blocks, effectively the C-equivalent of Rust's closures.
See the docs for a more thorough overview.
This crate is part of the objc2
project,
see that for related crates.
lib.rs
:
Apple's C language extension of blocks
C Blocks are effectively the C-equivalent of Rust's closures, in that they have the ability to capture their environments.
This crate provides capabilities to create and invoke these blocks, in an ergonomic "Rust-centric" fashion.
For more information on the specifics of the block implementation, see the C language specification and the ABI specification.
(Note that while this library can be used separately from Objective-C, they're most commonly used together).
Invoking blocks
The [Block
] struct is used for invoking blocks from Objective-C. For
example, consider this Objective-C function that takes a block as a
parameter, executes the block with some arguments, and returns the result:
#include <stdint.h>
#include <Block.h>
int32_t run_block(int32_t (^block)(int32_t, int32_t)) {
return block(5, 8);
}
We could write the equivalent function in Rust like this:
use block2::Block;
unsafe fn run_block(block: &Block<(i32, i32), i32>) -> i32 {
block.call((5, 8))
}
Note the extra parentheses in the call
method, since the arguments must
be passed as a tuple.
Creating blocks
Creating a block to pass to Objective-C can be done with the
[ConcreteBlock
] struct. For example, to create a block that adds two
integers, we could write:
use block2::ConcreteBlock;
let block = ConcreteBlock::new(|a: i32, b: i32| a + b);
let block = block.copy();
assert_eq!(unsafe { block.call((5, 8)) }, 13);
It is important to copy your block to the heap (with the copy
method)
before passing it to Objective-C; this is because our [ConcreteBlock
] is
only meant 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.
As an optimization if your block doesn't capture any variables, you can
use the [global_block!
] macro to create a static block:
use block2::global_block;
global_block! {
static MY_BLOCK = || -> f32 {
10.0
};
}
assert_eq!(unsafe { MY_BLOCK.call(()) }, 10.0);