diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index afc7e1093..36b0e75e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 @@ -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 @@ -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 @@ -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 @@ -688,7 +690,7 @@ jobs: ~/extern/lib ~/extern/include # Change this key if we start caching more things - key: extern-${{ github.job }}-${{ matrix.name }}-v1 + key: extern-${{ github.job }}-${{ matrix.name }}-v2 - name: Setup environment # These add to PATH-like variables, so they can always be set @@ -721,6 +723,19 @@ jobs: if: steps.extern-cache.outputs.cache-hit != 'true' run: sudo apt-get -y install make cmake + - name: Install libdispatch + if: steps.extern-cache.outputs.cache-hit != 'true' + run: | + wget https://github.com/swiftlang/swift-corelibs-libdispatch/archive/refs/tags/swift-6.0.3-RELEASE.tar.gz + tar -xzf swift-6.0.3-RELEASE.tar.gz + cd swift-corelibs-libdispatch-swift-6.0.3-RELEASE + + mkdir build + cd build + cmake -Wno-dev -DCMAKE_INSTALL_PREFIX=$HOME/extern .. + make install + ls -al $HOME/extern/* + - name: Install GNUStep libobjc2 if: steps.extern-cache.outputs.cache-hit != 'true' run: | diff --git a/Cargo.lock b/Cargo.lock index d995a155c..c01268d49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,6 +180,13 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.1.0" +dependencies = [ + "libc", +] + [[package]] name = "equivalent" version = "1.0.1" diff --git a/README.md b/README.md index 0cf8b3fb4..5772c3860 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,12 @@ The crates you're interested in is probably: it, we [aim to have it](https://github.com/madsmtm/objc2/issues/393)). - [`block2`], which provides bindings for Apple's C blocks, the C-equivalent of a Rust closure. +- [`dispatch2`], which provides bindings for Apple's Grand Central Dispatch. [`objc2`]: ./crates/objc2 [`objc2-*`]: ./framework-crates [`block2`]: ./crates/block2 +[`dispatch2`]: ./crates/dispatch2 ## Contact Us @@ -151,6 +153,8 @@ fork [here](https://github.com/SSheldon/rust-objc/issues/101): These were created almost solely by [@SSheldon](https://github.com/SSheldon), so a huge thanks for their fantastic work on these crates! +Additionally, the `dispatch2` crate originally lived [here](https://github.com/marysaka/dispatch2). + This project also draws inspiration from: - [`apple-sys`](https://github.com/youknowone/apple-sys) - [`cacao`](https://github.com/ryanmcgrath/cacao) @@ -163,6 +167,7 @@ This project also draws inspiration from: - [`uikit-sys`](https://github.com/simlay/uikit-sys) and `@simlay`'s [Objective-C work on `bindgen`](https://rust-lang.github.io/rust-bindgen/objc.html) - [`cidre`](https://github.com/yury/cidre) - [the `apple-media` project](https://github.com/rust-media/apple-media-rs) +- [`dispatch`](https://github.com/SSheldon/rust-dispatch) Finally, this is by far not the only project that ever tried to interoperate with Objective-C; other languages have done so as well (to varying degrees of success): - Swift: Built from the beginning for Objective-C interop, and is what `objc2` aspires to have feature-parity with (though will probably never reach). Truly beautifully designed language! diff --git a/crates/block2/Cargo.toml b/crates/block2/Cargo.toml index 56651ee6e..764949609 100644 --- a/crates/block2/Cargo.toml +++ b/crates/block2/Cargo.toml @@ -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"] diff --git a/crates/block2/src/encoding.rs b/crates/block2/src/encoding.rs index 52942970c..dc1ab2784 100644 --- a/crates/block2/src/encoding.rs +++ b/crates/block2/src/encoding.rs @@ -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() -> CString +pub(crate) fn block_signature_string() -> CString where A: EncodeArguments, R: EncodeReturn, diff --git a/crates/dispatch2/CHANGELOG.md b/crates/dispatch2/CHANGELOG.md new file mode 100644 index 000000000..67b1d892c --- /dev/null +++ b/crates/dispatch2/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +Notable changes to this crate will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## Unreleased - YYYY-MM-DD + +### Changed +- Moved to the `objc2` project. + + +## 0.1.0 - 2022-10-02 + +Initial version. diff --git a/crates/dispatch2/Cargo.toml b/crates/dispatch2/Cargo.toml index 1f31d697c..6aaaff0af 100644 --- a/crates/dispatch2/Cargo.toml +++ b/crates/dispatch2/Cargo.toml @@ -1,18 +1,42 @@ [package] name = "dispatch2" -version = "0.1.0" -authors = ["Mary "] +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 ", "Mary "] +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 = [] diff --git a/crates/dispatch2/README.md b/crates/dispatch2/README.md index cbbae31a3..b486c0f2d 100644 --- a/crates/dispatch2/README.md +++ b/crates/dispatch2/README.md @@ -1,31 +1,17 @@ -# dispatch2 +# `dispatch2` -Allows interaction with the [Apple Dispatch](https://developer.apple.com/documentation/dispatch) library in a safe and unsafe way. +[![Latest version](https://badgen.net/crates/v/dispatch2)](https://crates.io/crates/dispatch2) +[![License](https://badgen.net/static/license/MIT%20OR%20Apache%202.0/blue)](https://github.com/madsmtm/objc2/blob/master/LICENSE.txt) +[![Documentation](https://docs.rs/dispatch2/badge.svg)](https://docs.rs/dispatch2/) +[![CI](https://github.com/madsmtm/objc2/actions/workflows/ci.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/ci.yml) -## Usage +Apple's Grand Central Dispatch interface in Rust. -To use `dispatch2`, add this to your `Cargo.toml`: +This crate provides a safe and sound interface to Apple's Grand Central +dispatch, as well as the ability to drop into lower-level bindings. -```toml -[dependencies] -dispatch2 = "0.1.0" -``` +This README is kept intentionally small in an effort to consolidate the +documentation, see [the Rust docs](https://docs.rs/dispatch2/) for more details. -## Example - -```rust -use dispatch2::{Queue, QueueAttribute}; - -fn main() { - let queue = Queue::new("example_queue", QueueAttribute::Serial); - queue.exec_async(|| println!("Hello")); - queue.exec_sync(|| println!("World")); -} -``` - -## License - -dispatch2 is distributed under the terms of either the MIT license or the Apache -License (Version 2.0), at the user's choice. - -See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT). +This crate is part of the [`objc2` project](https://github.com/madsmtm/objc2), +see that for related crates. diff --git a/crates/dispatch2/TODO.md b/crates/dispatch2/TODO.md index dd3ec4ce9..f96c1ba1d 100644 --- a/crates/dispatch2/TODO.md +++ b/crates/dispatch2/TODO.md @@ -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. diff --git a/crates/dispatch2/src/ffi.rs b/crates/dispatch2/src/ffi.rs index 756d6c5f4..61d2dbafc 100644 --- a/crates/dispatch2/src/ffi.rs +++ b/crates/dispatch2/src/ffi.rs @@ -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 @@ -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), @@ -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); @@ -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( @@ -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); @@ -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. diff --git a/crates/dispatch2/src/group.rs b/crates/dispatch2/src/group.rs index b2fc46efd..7fdcd44d4 100644 --- a/crates/dispatch2/src/group.rs +++ b/crates/dispatch2/src/group.rs @@ -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 }) } @@ -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::(); // Safety: All parameters cannot be null. unsafe { @@ -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::(); // Safety: All parameters cannot be null. unsafe { @@ -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() } } } diff --git a/crates/dispatch2/src/lib.rs b/crates/dispatch2/src/lib.rs index 631833f75..8101a5391 100644 --- a/crates/dispatch2/src/lib.rs +++ b/crates/dispatch2/src/lib.rs @@ -1,26 +1,22 @@ -#![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. //! -//! # Example: +//! ## Example //! //! ``` //! 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)] +// Update in Cargo.toml as well. +#![doc(html_root_url = "https://docs.rs/dispatch2/0.1.0")] use self::ffi::dispatch_qos_class_t; diff --git a/crates/dispatch2/src/object.rs b/crates/dispatch2/src/object.rs index d1a0371b1..5547ee2e7 100644 --- a/crates/dispatch2/src/object.rs +++ b/crates/dispatch2/src/object.rs @@ -52,7 +52,7 @@ impl DispatchObject { // Safety: We own a reference to the object. unsafe { - dispatch_retain(result.object as *mut _); + dispatch_retain(result.object.cast()); } result @@ -63,14 +63,14 @@ impl DispatchObject { 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::) + dispatch_set_context(self.object.cast(), destructor_boxed); + dispatch_set_finalizer_f(self.object.cast(), function_wrapper::) } } @@ -84,9 +84,9 @@ impl DispatchObject { 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(()) @@ -106,10 +106,10 @@ impl DispatchObject { 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, ); @@ -122,7 +122,7 @@ impl DispatchObject { 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; @@ -132,7 +132,7 @@ impl DispatchObject { pub fn suspend(&self) { // Safety: object cannot be null. unsafe { - dispatch_suspend(self.as_raw() as *mut _); + dispatch_suspend(self.as_raw().cast()); } } @@ -140,7 +140,7 @@ impl DispatchObject { pub fn resume(&self) { // Safety: object cannot be null. unsafe { - dispatch_resume(self.as_raw() as *mut _); + dispatch_resume(self.as_raw().cast()); } } @@ -165,7 +165,7 @@ impl Drop for DispatchObject { fn drop(&mut self) { // Safety: We own a reference to the object. unsafe { - dispatch_release(self.object as *mut _); + dispatch_release(self.object.cast()); } } } diff --git a/crates/dispatch2/src/queue.rs b/crates/dispatch2/src/queue.rs index 3e6094452..898abb065 100644 --- a/crates/dispatch2/src/queue.rs +++ b/crates/dispatch2/src/queue.rs @@ -137,7 +137,7 @@ impl Queue { assert!(!object.is_null(), "dispatch_queue_create shouldn't fail!"); // Safety: object cannot be null. - let dispatch_object = unsafe { DispatchObject::new_owned(object as *mut _) }; + let dispatch_object = unsafe { DispatchObject::new_owned(object.cast()) }; Queue { dispatch_object, @@ -161,7 +161,7 @@ impl Queue { assert!(!object.is_null(), "dispatch_queue_create shouldn't fail!"); // Safety: object cannot be null. - let dispatch_object = unsafe { DispatchObject::new_owned(object as *mut _) }; + let dispatch_object = unsafe { DispatchObject::new_owned(object.cast()) }; // NOTE: dispatch_queue_create_with_target is in charge of retaining the target Queue. @@ -171,7 +171,7 @@ impl Queue { } } - /// Return a system-defined global concurrent [Queue] with the priority derivated from [GlobalQueueIdentifier]. + /// Return a system-defined global concurrent [Queue] with the priority derived from [GlobalQueueIdentifier]. pub fn global_queue(identifier: GlobalQueueIdentifier) -> Self { let raw_identifier = identifier.to_identifier(); @@ -184,7 +184,7 @@ impl Queue { ); // Safety: object cannot be null. - let dispatch_object = unsafe { DispatchObject::new_shared(object as *mut _) }; + let dispatch_object = unsafe { DispatchObject::new_shared(object.cast()) }; Queue { dispatch_object, @@ -199,7 +199,7 @@ impl Queue { { assert!(!self.is_workloop, "exec_sync is invalid for WorkloopQueue"); - let work_boxed = Box::leak(Box::new(work)) as *mut F as *mut _; + let work_boxed = Box::into_raw(Box::new(work)).cast(); // Safety: object cannot be null and work is wrapped to avoid ABI incompatibility. unsafe { dispatch_sync_f(self.as_raw(), work_boxed, function_wrapper::) } @@ -210,7 +210,7 @@ impl Queue { where F: Send + FnOnce(), { - let work_boxed = Box::leak(Box::new(work)) as *mut F as *mut _; + let work_boxed = Box::into_raw(Box::new(work)).cast(); // Safety: object cannot be null and work is wrapped to avoid ABI incompatibility. unsafe { dispatch_async_f(self.as_raw(), work_boxed, function_wrapper::) } @@ -223,7 +223,7 @@ impl Queue { { let when = dispatch_time_t::try_from(wait_time).map_err(|_| QueueAfterError::TimeOverflow)?; - let work_boxed = Box::leak(Box::new(work)) as *mut F as *mut _; + let work_boxed = Box::into_raw(Box::new(work)).cast(); // Safety: object cannot be null and work is wrapped to avoid ABI incompatibility. unsafe { @@ -238,7 +238,7 @@ impl Queue { where F: Send + FnOnce(), { - let work_boxed = Box::leak(Box::new(work)) as *mut F as *mut _; + let work_boxed = Box::into_raw(Box::new(work)).cast(); // Safety: object cannot be null and work is wrapped to avoid ABI incompatibility. unsafe { dispatch_barrier_async_f(self.as_raw(), work_boxed, function_wrapper::) } @@ -249,7 +249,7 @@ impl Queue { where F: Send + FnOnce(), { - let work_boxed = Box::leak(Box::new(work)) as *mut F as *mut _; + let work_boxed = Box::into_raw(Box::new(work)).cast(); // Safety: object cannot be null and work is wrapped to avoid ABI incompatibility. unsafe { dispatch_barrier_sync_f(self.as_raw(), work_boxed, function_wrapper::) } @@ -260,7 +260,7 @@ impl Queue { where F: Send + FnOnce(), { - let work_boxed = Box::leak(Box::new(work)) as *mut F as *mut _; + let work_boxed = Box::into_raw(Box::new(work)).cast(); // Safety: object cannot be null and work is wrapped to avoid ABI incompatibility. unsafe { @@ -273,7 +273,7 @@ impl Queue { 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: object cannot be null and destructor is wrapped to avoid ABI incompatibility. unsafe { @@ -334,7 +334,8 @@ impl Queue { /// /// - Object shouldn't be released manually. pub const unsafe fn as_raw(&self) -> dispatch_queue_t { - self.dispatch_object.as_raw() + // SAFETY: Upheld by caller. + unsafe { self.dispatch_object.as_raw() } } } @@ -361,7 +362,7 @@ impl WorkloopQueue { assert!(!object.is_null(), "dispatch_queue_create shouldn't fail!"); // Safety: object cannot be null. - let dispatch_object = unsafe { DispatchObject::new_owned(object as *mut _) }; + let dispatch_object = unsafe { DispatchObject::new_owned(object.cast()) }; WorkloopQueue { queue: Queue { @@ -388,7 +389,8 @@ impl WorkloopQueue { /// /// - Object shouldn't be released manually. pub const unsafe fn as_raw(&self) -> dispatch_workloop_t { - self.queue.as_raw() as dispatch_workloop_t + // SAFETY: Upheld by caller. + unsafe { self.queue.as_raw() as dispatch_workloop_t } } } diff --git a/crates/dispatch2/src/semaphore.rs b/crates/dispatch2/src/semaphore.rs index 443dd5feb..4d302cdfd 100644 --- a/crates/dispatch2/src/semaphore.rs +++ b/crates/dispatch2/src/semaphore.rs @@ -30,12 +30,12 @@ impl Semaphore { } // 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(Semaphore { dispatch_object }) } - /// Attempt to aquire the [Semaphore] and return a [SemaphoreGuard]. + /// Attempt to acquire the [Semaphore] and return a [SemaphoreGuard]. /// /// # Errors /// @@ -72,7 +72,8 @@ impl Semaphore { /// /// - Object shouldn't be released manually. pub const unsafe fn as_raw(&self) -> dispatch_semaphore_t { - self.dispatch_object.as_raw() + // SAFETY: Upheld by caller. + unsafe { self.dispatch_object.as_raw() } } } diff --git a/crates/dispatch2/src/utils.rs b/crates/dispatch2/src/utils.rs index 59e9301ff..5c6c08050 100644 --- a/crates/dispatch2/src/utils.rs +++ b/crates/dispatch2/src/utils.rs @@ -25,7 +25,7 @@ where F: FnOnce(), { // Safety: we reconstruct from a Box. - let work = unsafe { Box::from_raw(work_boxed as *mut F) }; + let work = unsafe { Box::from_raw(work_boxed.cast::()) }; (*work)(); }