Skip to content

Commit d76b73f

Browse files
committed
Refactor dispatch2
1 parent e6eda12 commit d76b73f

File tree

10 files changed

+626
-431
lines changed

10 files changed

+626
-431
lines changed

crates/dispatch2/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ targets = [
3838
]
3939

4040
[features]
41-
default = ["std"]
41+
default = ["std", "objc2"]
4242

4343
# Currently not possible to turn off, put here for forwards compatibility.
4444
std = ["alloc", "bitflags/std", "block2?/std", "libc?/std", "objc2?/std"]

crates/dispatch2/src/ffi.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
33
#![allow(missing_docs, non_camel_case_types)]
44

5-
use core::ffi::{c_long, c_uint, c_ulong, c_void};
6-
use std::ptr::addr_of;
5+
use std::{
6+
ffi::{c_long, c_uint, c_ulong, c_void},
7+
ptr::addr_of,
8+
};
79

810
#[cfg(feature = "objc2")]
911
use objc2::encode::{Encode, Encoding, RefEncode};
@@ -108,10 +110,11 @@ create_opaque_type!(dispatch_io_s, dispatch_io_t);
108110

109111
/// A dispatch queue that executes blocks serially in FIFO order.
110112
pub const DISPATCH_QUEUE_SERIAL: dispatch_queue_attr_t = core::ptr::null_mut();
113+
111114
/// A dispatch queue that executes blocks concurrently.
112-
pub static DISPATCH_QUEUE_CONCURRENT: &dispatch_queue_attr_s = {
115+
pub const DISPATCH_QUEUE_CONCURRENT: dispatch_queue_attr_t = {
113116
// Safety: immutable external definition
114-
unsafe { &_dispatch_queue_attr_concurrent }
117+
unsafe { &_dispatch_queue_attr_concurrent as *const _ as dispatch_queue_attr_t }
115118
};
116119

117120
pub const DISPATCH_APPLY_AUTO: dispatch_queue_t = core::ptr::null_mut();

crates/dispatch2/src/group.rs

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,25 @@
11
//! Dispatch group definition.
22
3-
use std::time::Duration;
3+
use std::{ffi::c_void, time::Duration};
44

5-
use core::ffi::c_void;
6-
7-
use super::object::DispatchObject;
8-
use super::queue::Queue;
9-
use super::utils::function_wrapper;
10-
use super::{ffi::*, WaitError};
5+
use super::{ffi::*, function_wrapper, queue::Queue, rc::Retained, AsRawDispatchObject, WaitError};
116

127
/// Dispatch group.
13-
#[derive(Debug, Clone)]
8+
#[derive(Debug)]
149
pub struct Group {
15-
dispatch_object: DispatchObject<dispatch_group_s>,
10+
inner: Retained<dispatch_group_s>,
1611
}
1712

18-
/// Dispatch group guard.
19-
#[derive(Debug)]
20-
pub struct GroupGuard(Group, bool);
21-
2213
impl Group {
2314
/// Creates a new [Group].
2415
pub fn new() -> Option<Self> {
2516
// Safety: valid to call.
2617
let object = unsafe { dispatch_group_create() };
2718

28-
if object.is_null() {
29-
return None;
30-
}
31-
32-
// Safety: object cannot be null.
33-
let dispatch_object = unsafe { DispatchObject::new_owned(object.cast()) };
19+
// Safety: retained accepts null pointer.
20+
let inner = unsafe { Retained::from_raw(object)? };
3421

35-
Some(Group { dispatch_object })
22+
Some(Group { inner })
3623
}
3724

3825
/// Submit a function to a [Queue] and associates it with the [Group].
@@ -104,25 +91,44 @@ impl Group {
10491
GroupGuard(self.clone(), false)
10592
}
10693

107-
/// Set the finalizer function for the object.
108-
pub fn set_finalizer<F>(&mut self, destructor: F)
109-
where
110-
F: Send + FnOnce(),
111-
{
112-
self.dispatch_object.set_finalizer(destructor);
113-
}
114-
11594
/// Get the raw [dispatch_group_t] value.
11695
///
11796
/// # Safety
11897
///
11998
/// - Object shouldn't be released manually.
120-
pub const unsafe fn as_raw(&self) -> dispatch_group_t {
121-
// SAFETY: Upheld by caller
122-
unsafe { self.dispatch_object.as_raw() }
99+
pub fn as_raw(&self) -> dispatch_group_t {
100+
// Safety: Upheld by caller
101+
Retained::as_ptr(&self.inner).cast_mut()
123102
}
124103
}
125104

105+
impl Clone for Group {
106+
fn clone(&self) -> Self {
107+
Self {
108+
// Safety: pointer must be valid.
109+
inner: unsafe {
110+
Retained::retain(self.as_raw()).expect("failed to retain dispatch_group")
111+
},
112+
}
113+
}
114+
}
115+
116+
impl AsRawDispatchObject for Group {
117+
fn as_raw_object(&self) -> dispatch_object_t {
118+
self.as_raw().cast()
119+
}
120+
}
121+
122+
// Safety: group is inherently safe to move between threads.
123+
unsafe impl Send for Group {}
124+
125+
// Safety: group is inherently safe to share between threads.
126+
unsafe impl Sync for Group {}
127+
128+
/// Dispatch group guard.
129+
#[derive(Debug)]
130+
pub struct GroupGuard(Group, bool);
131+
126132
impl GroupGuard {
127133
/// Explicitly indicates that the function in the [Group] finished executing.
128134
pub fn leave(mut self) {

crates/dispatch2/src/lib.rs

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
// Update in Cargo.toml as well.
2525
#![doc(html_root_url = "https://docs.rs/dispatch2/0.1.0")]
2626

27-
use self::ffi::dispatch_qos_class_t;
28-
2927
pub mod ffi;
3028
#[allow(clippy::undocumented_unsafe_blocks)]
3129
mod generated;
@@ -35,8 +33,22 @@ mod main_thread_bound;
3533
pub mod object;
3634
mod once;
3735
pub mod queue;
36+
mod rc;
3837
pub mod semaphore;
39-
mod utils;
38+
pub mod workloop;
39+
40+
#[cfg(feature = "objc2")]
41+
pub use self::main_thread_bound::{run_on_main, MainThreadBound};
42+
pub use self::once::*;
43+
pub use group::*;
44+
pub use object::*;
45+
pub use queue::*;
46+
pub use semaphore::*;
47+
pub use workloop::*;
48+
49+
use std::{ffi::c_void, time::Duration};
50+
51+
use ffi::{dispatch_qos_class_t, dispatch_time, dispatch_time_t, DISPATCH_TIME_NOW};
4052

4153
/// Wait error.
4254
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -49,14 +61,15 @@ pub enum WaitError {
4961
}
5062

5163
/// Quality of service that specify the priorities for executing tasks.
52-
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
64+
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5365
#[non_exhaustive]
5466
pub enum QualityOfServiceClass {
5567
/// Quality of service for user-interactive tasks.
5668
UserInteractive,
5769
/// Quality of service for tasks that prevent the user from actively using your app.
5870
UserInitiated,
5971
/// Default Quality of service.
72+
#[default]
6073
Default,
6174
/// Quality of service for tasks that the user does not track actively.
6275
Utility,
@@ -82,10 +95,44 @@ impl From<QualityOfServiceClass> for dispatch_qos_class_t {
8295
}
8396
}
8497

85-
pub use self::group::*;
86-
#[cfg(feature = "objc2")]
87-
pub use self::main_thread_bound::{run_on_main, MainThreadBound};
88-
pub use self::object::*;
89-
pub use self::once::*;
90-
pub use self::queue::*;
91-
pub use self::semaphore::*;
98+
impl TryFrom<Duration> for dispatch_time_t {
99+
type Error = TryFromDurationError;
100+
101+
fn try_from(value: Duration) -> Result<Self, Self::Error> {
102+
let secs = value.as_secs() as i64;
103+
104+
secs.checked_mul(1_000_000_000)
105+
.and_then(|x| x.checked_add(i64::from(value.subsec_nanos())))
106+
.map(|delta| {
107+
// Safety: delta cannot overflow
108+
unsafe { dispatch_time(DISPATCH_TIME_NOW, delta) }
109+
})
110+
.ok_or(Self::Error::TimeOverflow)
111+
}
112+
}
113+
114+
/// Error returned by [Queue::after].
115+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
116+
#[non_exhaustive]
117+
pub enum TryFromDurationError {
118+
/// The given timeout value will result in an overflow when converting to dispatch time.
119+
TimeOverflow,
120+
}
121+
122+
/// Error returned by [Queue::set_qos_class_floor] or [WorkloopQueue::set_qos_class_floor].
123+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
124+
#[non_exhaustive]
125+
pub enum QualityOfServiceClassFloorError {
126+
/// The relative priority is invalid.
127+
InvalidRelativePriority,
128+
}
129+
130+
pub(crate) extern "C" fn function_wrapper<F>(work_boxed: *mut c_void)
131+
where
132+
F: FnOnce(),
133+
{
134+
// Safety: we reconstruct from a Box.
135+
let work = unsafe { Box::from_raw(work_boxed.cast::<F>()) };
136+
137+
(*work)();
138+
}

0 commit comments

Comments
 (0)