Skip to content

Commit

Permalink
Merge pull request #18 from madsmtm/objc_block
Browse files Browse the repository at this point in the history
Move `block` crate into this repo
  • Loading branch information
madsmtm authored Sep 2, 2021
2 parents 1f82d5b + 50704af commit 9480a6f
Show file tree
Hide file tree
Showing 21 changed files with 790 additions and 22 deletions.
9 changes: 4 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
- name: Install Packages
if: contains(matrix.platform.os, 'ubuntu')
run: sudo apt-get install gobjc clang make
run: sudo apt-get install gobjc clang make libblocksruntime-dev

- name: Install different Rust toolchain
# A default toolchain is already installed
Expand Down Expand Up @@ -120,12 +120,11 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
# TODO: `objc_foundation/block` feature doesn't work
args: --verbose --no-fail-fast --no-default-features

- name: Test w. exception and verify_message features
- name: Test with features
uses: actions-rs/cargo@v1
with:
command: test
# TODO: `objc_foundation/block` feature doesn't work
args: --verbose --no-fail-fast --no-default-features --features exception,verify_message
# Not using --all-features because some features are nightly-only
args: --verbose --no-fail-fast --features block,exception,verify_message
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
[workspace]
members = [
"objc",
"objc_block",
"objc_encode",
"objc_exception",
"objc_foundation",
"objc_foundation_derive",
"objc_id",
"objc_test_utils",
]
exclude = ["objc/tests-ios"]
6 changes: 4 additions & 2 deletions objc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ The bindings can be used on Linux or *BSD utilizing the
*/

#![no_std]
#![cfg_attr(feature = "unstable_autoreleasesafe", feature(negative_impls, auto_traits))]

#![cfg_attr(
feature = "unstable_autoreleasesafe",
feature(negative_impls, auto_traits)
)]
#![warn(missing_docs)]
#![allow(clippy::missing_safety_doc)]
// Update in Cargo.toml as well.
Expand Down
10 changes: 8 additions & 2 deletions objc/src/rc/autorelease.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::ffi::c_void;
#[cfg(all(debug_assertions, not(feature = "unstable_autoreleasesafe")))]
use std::{cell::RefCell, vec::Vec, thread_local};
use std::{cell::RefCell, thread_local, vec::Vec};

use crate::runtime::{objc_autoreleasePoolPop, objc_autoreleasePoolPush};

Expand Down Expand Up @@ -81,6 +81,7 @@ impl AutoreleasePool {
all(debug_assertions, not(feature = "unstable_autoreleasesafe")),
inline
)]
#[allow(clippy::needless_lifetimes)]
pub unsafe fn ptr_as_ref<'p, T>(&'p self, ptr: *const T) -> &'p T {
#[cfg(all(debug_assertions, not(feature = "unstable_autoreleasesafe")))]
POOLS.with(|c| {
Expand Down Expand Up @@ -110,6 +111,8 @@ impl AutoreleasePool {
all(debug_assertions, not(feature = "unstable_autoreleasesafe")),
inline
)]
#[allow(clippy::needless_lifetimes)]
#[allow(clippy::mut_from_ref)]
pub unsafe fn ptr_as_mut<'p, T>(&'p self, ptr: *mut T) -> &'p mut T {
#[cfg(all(debug_assertions, not(feature = "unstable_autoreleasesafe")))]
POOLS.with(|c| {
Expand Down Expand Up @@ -265,7 +268,10 @@ impl !AutoreleaseSafe for AutoreleasePool {}
/// inner pool:
///
#[cfg_attr(feature = "unstable_autoreleasesafe", doc = "```rust,compile_fail")]
#[cfg_attr(not(feature = "unstable_autoreleasesafe"), doc = "```rust,should_panic")]
#[cfg_attr(
not(feature = "unstable_autoreleasesafe"),
doc = "```rust,should_panic"
)]
/// # use objc::{class, msg_send};
/// # use objc::rc::{autoreleasepool, AutoreleasePool};
/// # use objc::runtime::Object;
Expand Down
27 changes: 27 additions & 0 deletions objc_block/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "block"
version = "0.1.6"
authors = ["Steven Sheldon", "Mads Marquart <mads@marquart.dk>"]
edition = "2018"

description = "Interface for Apple's C language extension of blocks."
keywords = ["objective-c", "macos", "ios", "blocks"]
categories = [
"api-bindings",
"development-tools::ffi",
"os::macos-apis",
]
readme = "README.md"
repository = "https://github.com/madsmtm/objc"
documentation = "https://docs.rs/block/"
license = "MIT"

exclude = [
"tests-ios/**",
]

[dependencies]
objc-encode = { path = "../objc_encode", version = "1.1.0" }

[dev-dependencies]
objc_test_utils = { path = "../objc_test_utils", version = "0.0" }
49 changes: 49 additions & 0 deletions objc_block/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# `block`

[![Latest version](https://badgen.net/crates/v/block)](https://crates.io/crates/block)
[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt)
[![Documentation](https://docs.rs/block/badge.svg)](https://docs.rs/block/)
[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions)

Rust interface for Apple's C language extension of blocks.

For more information on the specifics of the block implementation, see
Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html

## Invoking blocks

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
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
let block = ConcreteBlock::new(|a: i32, b: i32| a + b);
let block = block.copy();
assert!(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.
Loading

0 comments on commit 9480a6f

Please sign in to comment.