Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# [![Rust + \[Obj-C\]](assets/logo-small.png)](https://github.com/madsmtm/objc2) <br> Objective-C in Rust

[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt)
[![Apple CI](https://github.com/madsmtm/objc2/actions/workflows/apple.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/apple.yml)
[![GNUStep CI](https://github.com/madsmtm/objc2/actions/workflows/gnustep.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/gnustep.yml)
[![CI](https://github.com/madsmtm/objc2/actions/workflows/ci.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/ci.yml)

# DISCLAIMER! These crates are work in progress, and should not be used in production environments. Use the battle-tested `objc` family instead!

Anyway, thanks for being here, any help testing things out is highly
appreciated!


## Migrating from original crates

Expand Down
13 changes: 10 additions & 3 deletions block-sys/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
[![Latest version](https://badgen.net/crates/v/block-sys)](https://crates.io/crates/block-sys)
[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt)
[![Documentation](https://docs.rs/block-sys/badge.svg)](https://docs.rs/block-sys/)
[![Apple CI](https://github.com/madsmtm/objc2/actions/workflows/apple.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/apple.yml)
[![GNUStep CI](https://github.com/madsmtm/objc2/actions/workflows/gnustep.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/gnustep.yml)
[![CI](https://github.com/madsmtm/objc2/actions/workflows/ci.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/ci.yml)

Raw Rust bindings to Apple's C language extension of blocks.

This crate is part of the [`objc2` project](https://github.com/madsmtm/objc2),
see that for related crates.


## Runtime Support

This library is basically just a raw interface to the aptly specified [Blocks
Expand All @@ -17,7 +20,9 @@ several different helper functions), the most important aspect being that the
libraries are named differently, so the linking must take that into account.

The user can choose the desired runtime by using the relevant cargo feature
flags, see the following sections:
flags, see the following sections. Note that if the `objc-sys` crate is
present in the module tree, this should have the same feature flag enabled as
that.


### Apple's [`libclosure`](https://opensource.apple.com/source/libclosure/)
Expand Down Expand Up @@ -52,6 +57,8 @@ and is now used in [Swift's `libdispatch`] and [Swift's Foundation] as well.
This can be easily used on many Linux systems with the `libblocksruntime-dev`
package.

Using this runtime probably won't work together with `objc-sys` 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

Expand Down
5 changes: 3 additions & 2 deletions block-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
//! sources, but the [ABI specification][ABI] is really the place you should
//! be looking!
//!
//! See also the `README.md` for more info.
//! See also the [`README.md`](https://crates.io/crates/block-sys) for more
//! background information, and for how to configure the desired runtime.
//!
//! [ABI]: https://clang.llvm.org/docs/Block-ABI-Apple.html

Expand Down Expand Up @@ -257,7 +258,7 @@ pub struct Block_layout {
/// space on the stack allocated to hold the return value.
pub invoke: Option<unsafe extern "C" fn(block: *mut Block_layout, ...)>,
/// The block's descriptor. The actual type of this is:
/// ```ignore
/// ```pseudo-code
/// match (BLOCK_HAS_COPY_DISPOSE, BLOCK_HAS_SIGNATURE) {
/// (false, false) => Block_descriptor_header,
/// (true, false) => Block_descriptor,
Expand Down
4 changes: 4 additions & 0 deletions block2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased - YYYY-MM-DD

### Changed
* Changed `global_block!` macro to take an optional semicolon at the end.
* Improved documentation.


## 0.2.0-alpha.2 - 2021-12-22

Expand Down
48 changes: 6 additions & 42 deletions block2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,14 @@
[![Latest version](https://badgen.net/crates/v/block2)](https://crates.io/crates/block2)
[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt)
[![Documentation](https://docs.rs/block2/badge.svg)](https://docs.rs/block2/)
[![Apple CI](https://github.com/madsmtm/objc2/actions/workflows/apple.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/apple.yml)
[![GNUStep CI](https://github.com/madsmtm/objc2/actions/workflows/gnustep.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/gnustep.yml)
[![CI](https://github.com/madsmtm/objc2/actions/workflows/ci.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/ci.yml)

Apple's C language extension of blocks in Rust.

For more information on the specifics of the block implementation, see
Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html
This crate provides functionality for interracting with C blocks, effectively
the C-equivalent of Rust's closures.

## Invoking blocks
See [the docs](https://docs.rs/block2/) for a more thorough overview.

The `Block` struct is used for invoking blocks from Objective-C. For example,
consider this Objective-C function:

```objc
int32_t sum(int32_t (^block)(int32_t, int32_t)) {
return block(5, 8);
}
```

We could write it in Rust as the following:

```rust
use block2::Block;
unsafe fn sum(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 `i32`s, we could write:

```rust
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.
This crate is part of the [`objc2` project](https://github.com/madsmtm/objc2),
see that for related crates.
50 changes: 31 additions & 19 deletions block2/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ where
/// global_block! {
/// static MY_BLOCK = || -> i32 {
/// 42
/// }
/// };
/// };
/// }
/// assert_eq!(unsafe { MY_BLOCK.call(()) }, 42);
/// ```
///
Expand All @@ -109,8 +109,8 @@ where
/// global_block! {
/// static ADDER_BLOCK = |x: i32, y: i32| -> i32 {
/// x + y
/// }
/// };
/// };
/// }
/// assert_eq!(unsafe { ADDER_BLOCK.call((5, 7)) }, 12);
/// ```
///
Expand All @@ -119,8 +119,8 @@ where
/// global_block! {
/// pub static MUTATING_BLOCK = |x: &mut i32| {
/// *x = *x + 42;
/// }
/// };
/// };
/// }
/// let mut x = 5;
/// unsafe { MUTATING_BLOCK.call((&mut x,)) };
/// assert_eq!(x, 47);
Expand All @@ -131,8 +131,19 @@ where
/// ```compile_fail
/// use block2::global_block;
/// global_block! {
/// pub static INVALID_BLOCK = |b: Box<i32>| {}
/// };
/// pub static BLOCK = |b: Box<i32>| {};
/// }
/// ```
///
/// There is also no way to get a block function that's generic over it's
/// arguments. One could imagine the following syntax would work, but it can't
/// due to implementation limitations:
///
/// ```compile_fail
/// use block2::global_block;
/// global_block! {
/// pub static BLOCK<T: Encode> = |b: T| {};
/// }
/// ```
///
/// [`Box`]: std::boxed::Box
Expand All @@ -141,20 +152,23 @@ macro_rules! global_block {
// `||` is parsed as one token
(
$(#[$m:meta])*
$vis:vis static $name:ident = || $(-> $r:ty)? $body:block
$vis:vis static $name:ident = || $(-> $r:ty)? $body:block $(;)?
) => {
$crate::global_block!($(#[$m])* $vis static $name = |,| $(-> $r)? $body);
$crate::global_block!(
$(#[$m])*
$vis static $name = |,| $(-> $r)? $body
);
};
(
$(#[$m:meta])*
$vis:vis static $name:ident = |$($a:ident: $t:ty),* $(,)?| $(-> $r:ty)? $body:block
$vis:vis static $name:ident = |$($a:ident: $t:ty),* $(,)?| $(-> $r:ty)? $body:block $(;)?
) => {
$(#[$m])*
#[allow(unused_unsafe)]
$vis static $name: $crate::GlobalBlock<($($t,)*) $(, $r)?> = unsafe {
let mut layout = $crate::GlobalBlock::<($($t,)*) $(, $r)?>::__DEFAULT_LAYOUT;
layout.isa = &$crate::ffi::_NSConcreteGlobalBlock as *const _ as *mut _;
layout.invoke = Some({
layout.invoke = ::core::option::Option::Some({
unsafe extern "C" fn inner(_: *mut $crate::ffi::Block_layout, $($a: $t),*) $(-> $r)? {
$body
}
Expand All @@ -172,15 +186,15 @@ macro_rules! global_block {
mod tests {
global_block! {
/// Test comments and visibility
pub(super) static NOOP_BLOCK = || {}
pub(super) static NOOP_BLOCK = || {};
}

global_block! {
/// Multiple arguments + trailing comma
#[allow(unused)]
static BLOCK = |x: i32, y: i32, z: i32, w: i32,| -> i32 {
x + y + z + w
}
};
}

#[test]
Expand All @@ -190,11 +204,9 @@ mod tests {

#[test]
fn test_defined_in_function() {
global_block!(
static MY_BLOCK = || -> i32 {
42
}
);
global_block!(static MY_BLOCK = || -> i32 {
42
});
assert_eq!(unsafe { MY_BLOCK.call(()) }, 42);
}
}
Loading