13 unstable releases (3 breaking)

0.4.0 Dec 3, 2023
0.3.0 Jul 31, 2023
0.2.0 Jun 20, 2023
0.2.0-alpha.8 Feb 7, 2023
0.2.0-alpha.1 Nov 22, 2021

#9 in macOS and iOS APIs

Download history 28765/week @ 2023-12-15 19712/week @ 2023-12-22 28202/week @ 2023-12-29 39419/week @ 2024-01-05 39172/week @ 2024-01-12 42626/week @ 2024-01-19 40578/week @ 2024-01-26 43305/week @ 2024-02-02 46031/week @ 2024-02-09 41969/week @ 2024-02-16 43770/week @ 2024-02-23 51794/week @ 2024-03-01 46573/week @ 2024-03-08 49940/week @ 2024-03-15 52778/week @ 2024-03-22 48799/week @ 2024-03-29

206,560 downloads per month
Used in 7 crates (6 directly)

MIT license

740KB
13K SLoC

block2

Latest version License Documentation CI

Apple's C language extension of blocks in Rust.

This crate provides functionality for interracting with C blocks, which is the C-equivalent of Rust's closures.

They are technically not limited to only being used in Objective-C, though in practice it's likely the only place you'll ever encounter them.

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 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);

Dependencies