Skip to content

Commit

Permalink
Various cleanups in dispatch2
Browse files Browse the repository at this point in the history
- Add to CI.
- Update to 2021 edition.
- Support visionOS and watchOS.
- Align Cargo.toml metadata with the rest of the project.
- Fix typos.
- Appease Clippy.
- Prefer `Box::into_raw` over `Box::leak`.

Part of #77.
  • Loading branch information
madsmtm committed Dec 17, 2024
1 parent 84730a4 commit f7e41e9
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 85 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ env:
#
# This excludes `header-translator`, `test-assembly`, `tests` and `test-ui`.
PUBLIC_CRATES: >-
--package=dispatch2
--package=block2
--package=objc2
--package=objc2-encode
Expand Down Expand Up @@ -113,12 +114,12 @@ jobs:
target: armv7s-apple-ios
build-std: true
# `cc` works poorly when cross-compiling, so let's ignore `objc2-exception-helper` for now.
args: --package=block2 --package=objc2 --package=objc2-encode --package=objc2-proc-macros $FRAMEWORKS_IOS_17 $INTERESTING_FEATURES -Zbuild-std
args: --package=dispatch2 --package=block2 --package=objc2 --package=objc2-encode --package=objc2-proc-macros $FRAMEWORKS_IOS_17 $INTERESTING_FEATURES -Zbuild-std
- name: visionOS Aarch64 simulator
target: aarch64-apple-visionos-sim
build-std: true
# `cc` works poorly when cross-compiling, so let's ignore `objc2-exception-helper` for now.
args: --package=block2 --package=objc2 --package=objc2-encode --package=objc2-proc-macros $FRAMEWORKS_VISIONOS_1 $INTERESTING_FEATURES -Zbuild-std
args: --package=dispatch2 --package=block2 --package=objc2 --package=objc2-encode --package=objc2-proc-macros $FRAMEWORKS_VISIONOS_1 $INTERESTING_FEATURES -Zbuild-std

- name: GNUStep + exceptions
target: x86_64-unknown-linux-gnu
Expand Down Expand Up @@ -198,7 +199,7 @@ jobs:
key: cargo-${{ github.job }}-${{ matrix.name }}-${{ hashFiles('**/Cargo.lock') }}

- name: cargo check
run: cargo check --package=block2 --package=objc2 --package=objc2-encode --package=objc2-proc-macros $FRAMEWORKS_MACOS_14 --features=all
run: cargo check --package=dispatch2 --package=block2 --package=objc2 --package=objc2-encode --package=objc2-proc-macros $FRAMEWORKS_MACOS_14 --features=all
env:
RUSTFLAGS: "--codegen=debuginfo=0" # Removed --deny=warnings

Expand Down Expand Up @@ -657,6 +658,7 @@ jobs:
RUNTIME_VERSION: gnustep-${{ matrix.libobjc2 }}
# Exclude `objc2-exception-helper`, for some reason that can't be tested directly on GNUStep
PUBLIC_CRATES: >-
--package=dispatch2
--package=block2
--package=objc2
--package=objc2-encode
Expand Down
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions crates/block2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ rust-version.workspace = true
repository.workspace = true
license = "MIT" # https://github.com/madsmtm/objc2/issues/23

[lints]
workspace = true

[features]
default = ["std"]

Expand Down
2 changes: 1 addition & 1 deletion crates/block2/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use objc2::encode::{EncodeArguments, EncodeReturn, Encoding};
/// assert_eq!(block_signature_string::<(i32, f32), u8>(), "C16@?0i8f12");
/// ```
#[allow(unused)]
pub fn block_signature_string<A, R>() -> CString
pub(crate) fn block_signature_string<A, R>() -> CString
where
A: EncodeArguments,
R: EncodeReturn,
Expand Down
46 changes: 35 additions & 11 deletions crates/dispatch2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
[package]
name = "dispatch2"
version = "0.1.0"
authors = ["Mary <mary@mary.zone>"]
version = "0.1.0" # Remember to update html_root_url in lib.rs
description = "Bindings and wrappers for Apple's Grand Central Dispatch (GCD)"
keywords = ["gcd", "macos", "ios", "dispatch", "libdispatch"]
categories = [
"api-bindings",
"development-tools::ffi",
"os::macos-apis",
"external-ffi-bindings",
]
authors = ["Mads Marquart <mads@marquart.dk>", "Mary <mary@mary.zone>"]
edition.workspace = true
rust-version.workspace = true
repository.workspace = true
license = "Apache-2.0 OR MIT"
repository = "https://www.github.com/marysaka/dispatch2.git"
homepage = "https://www.github.com/marysaka/dispatch2"
description = "Bindings and wrappers for the Grand Central Dispatch (GCD)"
keywords = ["gcd", "macOS", "iOS", "watchOS", "ipadOS"]
categories = ["api-bindings", "development-tools::ffi", "os::macos-apis"]
edition = "2021"

exclude = [
".github"
]
[lints]
workspace = true

[dependencies]
libc = "0.2"

[package.metadata.docs.rs]
default-target = "aarch64-apple-darwin"
features = []
targets = [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
"aarch64-apple-ios",
"x86_64-apple-ios",
"aarch64-apple-tvos",
"aarch64-apple-watchos",
"aarch64-apple-ios-macabi",
"x86_64-unknown-linux-gnu",
"i686-unknown-linux-gnu",
]

[package.metadata.release]
shared-version = false
tag-prefix = "dispatch"
enable-features = []
2 changes: 1 addition & 1 deletion crates/dispatch2/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
- CI test on Windows using https://github.com/apple/swift-corelibs-libdispatch
- Safe wrapper for ``dispatch_source_*`` + ``set_target_queue/activate/suspend/resume`` for it
- Safe wrapper for ``dispatch_data_*``
- Safe wrapper for ``dispatch_once_f`` (is that relevent?)
- Safe wrapper for ``dispatch_once_f`` (is that relevant?)
- Safe wrapper for ``dispatch_get_context/dispatch_set_context`` (quite impossible without big overhead => wrap dispatch object destructor to release the boxed value)
- All blocks related bindings and ``dispatch_block_*`` functions with compat with ``block2`` on Apple platforms.
- Integrate conversion from SystemTime to dispatch_time_t via dispatch_walltime and safe APIs using that.
30 changes: 9 additions & 21 deletions crates/dispatch2/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use core::ffi::{c_char, c_int, c_long, c_uint, c_ulong, c_void};
macro_rules! create_opaque_type {
($type_name: ident, $typedef_name: ident) => {
#[repr(C)]
#[derive(Debug)]
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)]
pub struct $type_name {
/// opaque value
Expand All @@ -32,7 +32,7 @@ macro_rules! enum_with_val {
}

impl ::core::fmt::Debug for $ident {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
match self {
$(&$ident::$variant => write!(f, "{}::{}", stringify!($ident), stringify!($variant)),)*
&$ident(v) => write!(f, "UNKNOWN({})", v),
Expand Down Expand Up @@ -191,14 +191,8 @@ enum_with_val! {
}
}

#[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "tvos"),
link(name = "System", kind = "dylib")
)]
#[cfg_attr(
not(any(target_os = "macos", target_os = "ios", target_os = "tvos")),
link(name = "dispatch", kind = "dylib")
)]
#[cfg_attr(target_vendor = "apple", link(name = "System", kind = "dylib"))]
#[cfg_attr(not(target_vendor = "apple"), link(name = "dispatch", kind = "dylib"))]
extern "C" {
/// Increments the reference count (the retain count) of a dispatch object.
pub fn dispatch_retain(object: dispatch_object_t);
Expand Down Expand Up @@ -391,7 +385,7 @@ extern "C" {
) -> dispatch_queue_attr_t;
/// Creates a new dispatch queue to which you can submit blocks.
#[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "tvos"),
target_vendor = "apple",
link_name = "dispatch_queue_create_with_target$V2"
)]
pub fn dispatch_queue_create_with_target(
Expand Down Expand Up @@ -459,18 +453,12 @@ extern "C" {
pub fn dispatch_queue_get_specific(queue: dispatch_queue_t, key: *const c_void) -> *mut c_void;
/// Returns the value for the key associated with the current dispatch queue.
pub fn dispatch_get_specific(key: *const c_void) -> *mut c_void;
#[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "tvos"),
link_name = "dispatch_assert_queue$V2"
)]
#[cfg_attr(target_vendor = "apple", link_name = "dispatch_assert_queue$V2")]
/// Generates an assertion if the current block is not running on the specified dispatch queue.
pub fn dispatch_assert_queue(queue: dispatch_queue_t);
/// Generates an assertion if the current block is not running as a barrier on the specified dispatch queue.
pub fn dispatch_assert_queue_barrier(queue: dispatch_queue_t);
#[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "tvos"),
link_name = "dispatch_assert_queue_not$V2"
)]
#[cfg_attr(target_vendor = "apple", link_name = "dispatch_assert_queue_not$V2")]
/// Generates an assertion if the current block is executing on the specified dispatch queue.
pub fn dispatch_assert_queue_not(queue: dispatch_queue_t);

Expand All @@ -486,11 +474,11 @@ extern "C" {
pub static _dispatch_source_type_data_replace: dispatch_source_type_s;
pub static _dispatch_source_type_mach_send: dispatch_source_type_s;
pub static _dispatch_source_type_memorypressure: dispatch_source_type_s;
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos"))]
#[cfg(target_vendor = "apple")]
pub static _dispatch_source_type_proc: dispatch_source_type_s;
pub static _dispatch_source_type_read: dispatch_source_type_s;
pub static _dispatch_source_type_timer: dispatch_source_type_s;
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos"))]
#[cfg(target_vendor = "apple")]
pub static _dispatch_source_type_vnode: dispatch_source_type_s;
pub static _dispatch_source_type_write: dispatch_source_type_s;
/// Creates a new dispatch source to monitor low-level system events.
Expand Down
9 changes: 5 additions & 4 deletions crates/dispatch2/src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Group {
}

// Safety: object cannot be null.
let dispatch_object = unsafe { DispatchObject::new_owned(object as *mut _) };
let dispatch_object = unsafe { DispatchObject::new_owned(object.cast()) };

Some(Group { dispatch_object })
}
Expand All @@ -40,7 +40,7 @@ impl Group {
where
F: Send + FnOnce(),
{
let work_boxed = Box::leak(Box::new(work)) as *mut _ as *mut c_void;
let work_boxed = Box::into_raw(Box::new(work)).cast::<c_void>();

// Safety: All parameters cannot be null.
unsafe {
Expand Down Expand Up @@ -81,7 +81,7 @@ impl Group {
where
F: Send + FnOnce(),
{
let work_boxed = Box::leak(Box::new(work)) as *mut _ as *mut c_void;
let work_boxed = Box::into_raw(Box::new(work)).cast::<c_void>();

// Safety: All parameters cannot be null.
unsafe {
Expand Down Expand Up @@ -118,7 +118,8 @@ impl Group {
///
/// - Object shouldn't be released manually.
pub const unsafe fn as_raw(&self) -> dispatch_group_t {
self.dispatch_object.as_raw()
// SAFETY: Upheld by caller
unsafe { self.dispatch_object.as_raw() }
}
}

Expand Down
22 changes: 8 additions & 14 deletions crates/dispatch2/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
#![allow(unused_unsafe, unreachable_patterns)]
#![deny(
missing_docs,
clippy::undocumented_unsafe_blocks,
clippy::missing_safety_doc
)]

//!
//! Apple Dispatch (Grand Central Dispatch)
//! # Apple's Dispatch (Grand Central Dispatch)
//!
//! This crate allows interaction with the [Apple Dispatch](https://developer.apple.com/documentation/dispatch) library in a safe (``dispatch2`` module) and unsafe (``ffi`` module) way.
//!
Expand All @@ -15,12 +7,14 @@
//! ```
//! use dispatch2::{Queue, QueueAttribute};
//!
//! fn main() {
//! let queue = Queue::new("example_queue", QueueAttribute::Serial);
//! queue.exec_async(|| println!("Hello"));
//! queue.exec_sync(|| println!("World"));
//! }
//! let queue = Queue::new("example_queue", QueueAttribute::Serial);
//! queue.exec_async(|| println!("Hello"));
//! queue.exec_sync(|| println!("World"));
//! ```
#![allow(unreachable_patterns)]
#![warn(missing_docs)]
#![warn(clippy::undocumented_unsafe_blocks)]
#![warn(clippy::missing_safety_doc)]

use self::ffi::dispatch_qos_class_t;

Expand Down
24 changes: 12 additions & 12 deletions crates/dispatch2/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl<T> DispatchObject<T> {

// Safety: We own a reference to the object.
unsafe {
dispatch_retain(result.object as *mut _);
dispatch_retain(result.object.cast());
}

result
Expand All @@ -63,14 +63,14 @@ impl<T> DispatchObject<T> {
where
F: Send + FnOnce(),
{
let destructor_boxed = Box::leak(Box::new(destructor)) as *mut F as *mut _;
let destructor_boxed = Box::into_raw(Box::new(destructor)).cast();

// Safety: As this use the dispatch object's context, and because we need some way to wrap the Rust function, we set the context.
// Once the finalizer is executed, the context will be dangling.
// This isn't an issue as the context shall not be accessed after the dispatch object is destroyed.
unsafe {
dispatch_set_context(self.object as *mut _, destructor_boxed);
dispatch_set_finalizer_f(self.object as *mut _, function_wrapper::<F>)
dispatch_set_context(self.object.cast(), destructor_boxed);
dispatch_set_finalizer_f(self.object.cast(), function_wrapper::<F>)
}
}

Expand All @@ -84,9 +84,9 @@ impl<T> DispatchObject<T> {
return Err(TargetQueueError::ObjectAlreadyActive);
}

// Safety: object and queue cannot be null.
// SAFETY: object and queue cannot be null.
unsafe {
dispatch_set_target_queue(self.as_raw() as *mut _, queue.as_raw());
dispatch_set_target_queue(self.as_raw().cast(), queue.as_raw());
}

Ok(())
Expand All @@ -106,10 +106,10 @@ impl<T> DispatchObject<T> {
return Err(QualityOfServiceClassFloorError::InvalidRelativePriority);
}

// Safety: Safe as relative_priority can only be valid.
// SAFETY: Safe as relative_priority can only be valid.
unsafe {
dispatch_set_qos_class_floor(
self.as_raw() as *mut _,
self.as_raw().cast(),
dispatch_qos_class_t::from(qos_class),
relative_priority,
);
Expand All @@ -122,7 +122,7 @@ impl<T> DispatchObject<T> {
pub fn activate(&mut self) {
// Safety: object cannot be null.
unsafe {
dispatch_activate(self.as_raw() as *mut _);
dispatch_activate(self.as_raw().cast());
}

self.is_activated = true;
Expand All @@ -132,15 +132,15 @@ impl<T> DispatchObject<T> {
pub fn suspend(&self) {
// Safety: object cannot be null.
unsafe {
dispatch_suspend(self.as_raw() as *mut _);
dispatch_suspend(self.as_raw().cast());
}
}

/// Resume the invocation of functions on the object.
pub fn resume(&self) {
// Safety: object cannot be null.
unsafe {
dispatch_resume(self.as_raw() as *mut _);
dispatch_resume(self.as_raw().cast());
}
}

Expand All @@ -165,7 +165,7 @@ impl<T> Drop for DispatchObject<T> {
fn drop(&mut self) {
// Safety: We own a reference to the object.
unsafe {
dispatch_release(self.object as *mut _);
dispatch_release(self.object.cast());
}
}
}
Loading

0 comments on commit f7e41e9

Please sign in to comment.