1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
//! # Apple's C language extension of blocks
//!
//! C Blocks are functions which capture their environments, i.e. the
//! C-equivalent of Rust's [`Fn`] closures. As they were originally developed
//! by Apple, they're often used in Objective-C code. This crate provides
//! capabilities to create, manage and invoke these blocks, in an ergonomic,
//! "Rust-centric" fashion.
//!
//! At a high level, this crate contains four types, each representing
//! different kinds of blocks, and different kinds of ownership.
//!
//! | `block2` type                            | Equivalent Rust type  |
//! | ---------------------------------------- | --------------------- |
//! | `&Block<dyn Fn() + 'a>`                  | `&dyn Fn() + 'a`      |
//! | `RcBlock<dyn Fn() + 'a>`                 | `Arc<dyn Fn() + 'a>`  |
//! | `StackBlock<'a, (), (), impl Fn() + 'a>` | `impl Fn() + 'a`      |
//! | `GlobalBlock<dyn Fn()>`                  | [`fn` item]           |
//!
//! For more information on the specifics of the block implementation, see the
//! [C language specification][lang] and the [ABI specification][ABI].
//!
//! [lang]: https://clang.llvm.org/docs/BlockLanguageSpec.html
//! [ABI]: http://clang.llvm.org/docs/Block-ABI-Apple.html
//! [`fn` item]: https://doc.rust-lang.org/reference/types/function-item.html
//!
//!
//! ## External functions using blocks
//!
//! To declare external functions or methods that takes blocks, use
//! `&Block<dyn Fn(Params) -> R>` or `Option<&Block<dyn Fn(Args) -> R>>`,
//! where `Params` is the parameter types, and `R` is the return type.
//!
//! In the next few examples, we're going to work with a function
//! `check_addition`, that takes as parameter a block that adds two integers,
//! and checks that the addition is correct.
//!
//! Such a function could be written in C like in the following.
//!
//! ```objc
//! #include <cassert>
//! #include <stdint.h>
//! #include <Block.h>
//!
//! void check_addition(int32_t (^block)(int32_t, int32_t)) {
//!     assert(block(5, 8) == 13);
//! }
//! ```
//!
//! An `extern "C" { ... }` declaration for that function would then be:
//!
//! ```
//! use block2::Block;
//!
//! extern "C" {
//!     fn check_addition(block: &Block<dyn Fn(i32, i32) -> i32>);
//! }
//! ```
//!
//! This can similarly be done inside external methods declared with
//! [`objc2::extern_methods!`].
//!
//! ```
//! use block2::Block;
//! use objc2::extern_methods;
//! #
//! # use objc2::ClassType;
//! # objc2::extern_class!(
//! #     struct MyClass;
//! #
//! #     unsafe impl ClassType for MyClass {
//! #         type Super = objc2::runtime::NSObject;
//! #         type Mutability = objc2::mutability::InteriorMutable;
//! #         const NAME: &'static str = "NSObject";
//! #     }
//! # );
//!
//! extern_methods!(
//!     unsafe impl MyClass {
//!         #[method(checkAddition:)]
//!         pub fn checkAddition(&self, block: &Block<dyn Fn(i32, i32) -> i32>);
//!     }
//! );
//! ```
//!
//! If the function/method allowed passing `NULL` blocks, the type would be
//! `Option<&Block<dyn Fn(i32, i32) -> i32>>` instead.
//!
//!
//! ## Invoking blocks
//!
//! We can also define the external function in Rust, and expose it to
//! Objective-C. To do this, we can use [`Block::call`] to invoke the block
//! inside the function.
//!
//! ```
//! use block2::Block;
//!
//! #[no_mangle]
//! extern "C" fn check_addition(block: &Block<dyn Fn(i32, i32) -> i32>) {
//!     assert_eq!(block.call((5, 8)), 13);
//! }
//! ```
//!
//! 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 [`RcBlock`] or
//! [`StackBlock`], depending on if you want to move the block to the heap,
//! or let the callee decide if it needs to do that.
//!
//! To call such a function / method, we could create a new block from a
//! closure using [`RcBlock::new`].
//!
//! ```
//! use block2::RcBlock;
//! #
//! # extern "C" fn check_addition(block: &block2::Block<dyn Fn(i32, i32) -> i32>) {
//! #     assert_eq!(block.call((5, 8)), 13);
//! # }
//!
//! let block = RcBlock::new(|a, b| a + b);
//! check_addition(&block);
//! ```
//!
//! This creates the block on the heap. If the external function you're
//! calling is not going to copy the block, it may be more performant if you
//! construct a [`StackBlock`] directly, using [`StackBlock::new`].
//!
//! Note that this requires that the closure is [`Clone`], as the external
//! code is allowed to copy the block to the heap in the future.
//!
//! ```
//! use block2::StackBlock;
//! #
//! # extern "C" fn check_addition(block: &block2::Block<dyn Fn(i32, i32) -> i32>) {
//! #     assert_eq!(block.call((5, 8)), 13);
//! # }
//!
//! let block = StackBlock::new(|a, b| a + b);
//! check_addition(&block);
//! ```
//!
//! As an optimization, if your closure doesn't capture any variables (as in
//! the above examples), you can use the [`global_block!`] macro to create a
//! static block.
//!
//! ```
//! use block2::global_block;
//! #
//! # extern "C" fn check_addition(block: &block2::Block<dyn Fn(i32, i32) -> i32>) {
//! #     assert_eq!(block.call((5, 8)), 13);
//! # }
//!
//! global_block! {
//!     static BLOCK = |a: i32, b: i32| -> i32 {
//!         a + b
//!     };
//! }
//!
//! check_addition(&BLOCK);
//! ```
//!
//!
//! ## Lifetimes
//!
//! When dealing with blocks, there can be quite a few lifetimes to keep in
//! mind.
//!
//! The most important one is the lifetime of the block's data, i.e. the
//! lifetime of the data in the closure contained in the block. This lifetime
//! can be specified as `'f` in `&Block<dyn Fn() + 'f>`.
//!
//! Note that `&Block<dyn Fn()>`, without any lifetime specifier, can be a bit
//! confusing, as the default depends on where it is typed. In function/method
//! signatures, it defaults to `'static`, but as the type of e.g. a `let`
//! binding, the lifetime may be inferred to be something smaller, see [the
//! reference][ref-dyn-lifetime] for details. If in doubt, either add a
//! `+ 'static` or `+ '_` to force an escaping or non-escaping block.
//!
//! Another lifetime is the lifetime of the currently held pointer, i.e. `'b`
//! in `&'b Block<dyn Fn()>`. This lifetime can be safely extended using
//! [`Block::copy`], so should prove to be little trouble (of course the
//! lifetime still can't be extended past the lifetime of the captured data
//! above).
//!
//! Finally, the block's parameter and return types can also contain
//! lifetimes, as `'a` and `'r` in `&Block<dyn Fn(&'a i32) -> &'r u32>`.
//! Unfortunately, these lifetimes are quite problematic and unsupported at
//! the moment, due to Rust trait limitations regarding higher-ranked trait
//! bounds. If you run into problems with this in a block that takes or
//! returns a reference, consider using the ABI-compatible `NonNull<T>`, or
//! transmute to a `'static` lifetime.
//!
//! [ref-dyn-lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes
//!
//!
//! ## Thread safety
//!
//! Thread-safe blocks are not yet representable in `block2`, and as such any
//! function that requires a thread-safe block must be marked `unsafe`.
//!
//!
//! ## Mutability
//!
//! Blocks are generally assumed to be shareable, and as such can only very
//! rarely be made mutable. In particular, there is no good way to prevent
//! re-entrancy.
//!
//! You will likely have to use interior mutability instead.
//!
//!
//! ## Specifying a runtime
//!
//! Different runtime implementations exist and act in slightly different ways
//! (and have several different helper functions), the most important aspect
//! being that the libraries are named differently, so we must take that into
//! account when linking.
//!
//! You can choose the desired runtime by using the relevant cargo feature
//! flags, see the following sections (you might have to disable the default
//! `"apple"` feature first).
//!
//!
//! ### Apple's [`libclosure`](https://github.com/apple-oss-distributions/libclosure)
//!
//! - Feature flag: `apple`.
//!
//! This is the most common and most sophisticated runtime, and it has quite a
//! lot more features than the specification mandates.
//!
//! The minimum required operating system versions are as follows (though in
//! practice Rust itself requires higher versions than this):
//!
//! - macOS: `10.6`
//! - iOS/iPadOS: `3.2`
//! - tvOS: `1.0`
//! - watchOS: `1.0`
//!
//! **This is used by default**, so you do not need to specify a runtime if
//! you're using this crate on of these platforms.
//!
//!
//! ### LLVM `compiler-rt`'s [`libBlocksRuntime`](https://github.com/llvm/llvm-project/tree/release/13.x/compiler-rt/lib/BlocksRuntime)
//!
//! - Feature flag: `compiler-rt`.
//!
//! This is a copy of Apple's older (around macOS 10.6) runtime, and is now
//! used in [Swift's `libdispatch`] and [Swift's Foundation] as well.
//!
//! The runtime and associated headers can be installed on many Linux systems
//! with the `libblocksruntime-dev` package.
//!
//! Using this runtime probably won't work together with `objc2` crate.
//!
//! [Swift's `libdispatch`]: https://github.com/apple/swift-corelibs-libdispatch/tree/swift-5.5.1-RELEASE/src/BlocksRuntime
//! [Swift's Foundation]: https://github.com/apple/swift-corelibs-foundation/tree/swift-5.5.1-RELEASE/Sources/BlocksRuntime
//!
//!
//! ### GNUStep's [`libobjc2`](https://github.com/gnustep/libobjc2)
//!
//! - Feature flag: `gnustep-1-7`, `gnustep-1-8`, `gnustep-1-9`, `gnustep-2-0`
//!   and `gnustep-2-1` depending on the version you're using.
//!
//! GNUStep is a bit odd, because it bundles blocks support into its
//! Objective-C runtime. This means we have to link to `libobjc`, and this is
//! done by depending on the `objc2` crate. A bit unorthodox, yes, but it
//! works.
//!
//! Sources:
//!
//! - [`Block.h`](https://github.com/gnustep/libobjc2/blob/v2.1/objc/blocks_runtime.h)
//! - [`Block_private.h`](https://github.com/gnustep/libobjc2/blob/v2.1/objc/blocks_private.h)
//!
//!
//! ### Microsoft's [`WinObjC`](https://github.com/microsoft/WinObjC)
//!
//! - Feature flag: `unstable-winobjc`.
//!
//! **Unstable: Hasn't been tested on Windows yet!**
//!
//! [A fork](https://github.com/microsoft/libobjc2) based on GNUStep's `libobjc2`
//! version 1.8.
//!
//!
//! ### [`ObjFW`](https://github.com/ObjFW/ObjFW)
//!
//! - Feature flag: `unstable-objfw`.
//!
//! **Unstable: Doesn't work yet!**
//!
//!
//! ## C Compiler configuration
//!
//! To our knowledge, only Clang supports blocks. To compile C or Objective-C
//! sources using these features, you should set [the `-fblocks` flag][flag].
//!
//! [flag]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fblocks

#![no_std]
#![warn(missing_docs)]
#![warn(clippy::missing_errors_doc)]
#![warn(clippy::missing_panics_doc)]
// Update in Cargo.toml as well.
#![doc(html_root_url = "https://docs.rs/block2/0.5.0")]
#![cfg_attr(feature = "unstable-docsrs", feature(doc_auto_cfg, doc_cfg_hide))]
#![cfg_attr(feature = "unstable-docsrs", doc(cfg_hide(doc)))]

extern crate alloc;
extern crate std;

#[cfg(doctest)]
#[doc = include_str!("../README.md")]
extern "C" {}

#[cfg(not(feature = "std"))]
compile_error!("The `std` feature currently must be enabled.");

#[cfg(not(any(
    feature = "apple",
    feature = "compiler-rt",
    feature = "gnustep-1-7",
    feature = "unstable-objfw",
)))]
compile_error!("A runtime must be selected");

#[cfg(any(
    all(feature = "apple", feature = "compiler-rt"),
    all(feature = "compiler-rt", feature = "gnustep-1-7"),
    all(feature = "gnustep-1-7", feature = "unstable-objfw"),
    all(feature = "unstable-objfw", feature = "apple"),
    all(feature = "apple", feature = "gnustep-1-7"),
    all(feature = "compiler-rt", feature = "unstable-objfw"),
))]
compile_error!("Only one runtime may be selected");

#[cfg(feature = "unstable-objfw")]
compile_error!("ObjFW is not yet supported");

// Link to `libclosure` (internally called `libsystem_blocks.dylib`), which is
// exported by `libSystem.dylib`.
//
// Note: Don't get confused by the presence of `System.framework`, it is a
// deprecated wrapper over the dynamic library, so we'd rather use the latter.
//
// Alternative: Only link to `libsystem_blocks.dylib`:
// println!("cargo:rustc-link-search=native=/usr/lib/system");
// println!("cargo:rustc-link-lib=dylib=system_blocks");
#[cfg_attr(feature = "apple", link(name = "System", kind = "dylib"))]
// Link to `libBlocksRuntime`.
#[cfg_attr(feature = "compiler-rt", link(name = "BlocksRuntime", kind = "dylib"))]
// Link to `libobjfw`, which provides the blocks implementation.
#[cfg_attr(feature = "unstable-objfw", link(name = "objfw", kind = "dylib"))]
extern "C" {}

// Don't link to anything on GNUStep; objc2 already does that for us!
//
// We do want to ensure linkage actually happens, though.
#[cfg(feature = "gnustep-1-7")]
extern crate objc2 as _;

mod abi;
mod block;
mod debug;
pub mod ffi;
mod global;
mod rc_block;
mod stack;
mod traits;

pub use self::block::Block;
pub use self::global::GlobalBlock;
pub use self::rc_block::RcBlock;
pub use self::stack::StackBlock;
pub use self::traits::{BlockFn, IntoBlock};

/// Deprecated alias for a `'static` `StackBlock`.
#[deprecated = "renamed to `StackBlock`"]
pub type ConcreteBlock<A, R, Closure> = StackBlock<'static, A, R, Closure>;

// Note: We could use `_Block_object_assign` and `_Block_object_dispose` to
// implement a `ByRef<T>` wrapper, which would behave like `__block` marked
// variables and have roughly the same memory management scheme as blocks.
//
// But I've yet to see the value in such a wrapper in Rust code compared to
// just using `Box`, `Rc` or `Arc`, and since `__block` variables are
// basically never exposed as part of a (public) function's API, we won't
// implement such a thing yet.