Skip to content

Commit e429f0a

Browse files
committed
Inline basically all dispatch2 wrapper functions
Fixes #816, at least well enough that you can build rustc on macOS 10.12 host. (`invoke_dispatch_once` still isn't inlined, but that's fine, it's generic, so it won't get instantiated unless it's used).
1 parent 81bc841 commit e429f0a

File tree

9 files changed

+48
-6
lines changed

9 files changed

+48
-6
lines changed

crates/dispatch2/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88

99
### Fixed
1010
- Fixed reference counting in `DispatchSemaphoreGuard::release`.
11+
- Inlined more functions. This should allow using this library on macOS 10.12 with `crate-type = ["dylib"]`.
1112

1213

1314
## [0.3.0] - 2025-04-19

crates/dispatch2/src/data.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ impl DispatchData {
1616
// pub const EMPTY: &Self = _dispatch_data_empty;
1717

1818
/// Get an empty [`DispatchData`].
19+
#[inline]
1920
pub fn empty() -> &'static Self {
2021
// SAFETY: The static is valid.
2122
unsafe { &_dispatch_data_empty }
@@ -24,6 +25,7 @@ impl DispatchData {
2425
/// Creates a dispatch data object with a copy of the given contiguous
2526
/// buffer of memory.
2627
#[cfg(feature = "block2")]
28+
#[inline]
2729
pub fn from_bytes(data: &[u8]) -> DispatchRetained<Self> {
2830
// TODO: Autogenerate?
2931
const DISPATCH_DATA_DESTRUCTOR_DEFAULT: crate::dispatch_block_t = ptr::null_mut();
@@ -44,6 +46,7 @@ impl DispatchData {
4446
/// Creates a dispatch data object with a reference to the given
4547
/// contiguous buffer of memory.
4648
#[cfg(feature = "block2")]
49+
#[inline]
4750
pub fn from_static_bytes(data: &'static [u8]) -> DispatchRetained<Self> {
4851
block2::global_block! {
4952
static NOOP_BLOCK = || {}
@@ -66,6 +69,7 @@ impl DispatchData {
6669
/// buffer of memory.
6770
#[cfg(feature = "alloc")]
6871
#[cfg(feature = "block2")]
72+
#[inline]
6973
pub fn from_boxed(data: alloc::boxed::Box<[u8]>) -> DispatchRetained<Self> {
7074
let data_len = data.len();
7175
let raw = alloc::boxed::Box::into_raw(data);
@@ -104,6 +108,7 @@ impl DispatchData {
104108
#[cfg(feature = "alloc")]
105109
#[cfg(feature = "block2")]
106110
#[cfg(feature = "objc2")]
111+
#[inline]
107112
pub fn to_vec(&self) -> alloc::vec::Vec<u8> {
108113
let contents = core::cell::RefCell::new(alloc::vec::Vec::new());
109114
let block = block2::RcBlock::new(

crates/dispatch2/src/group.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ dispatch_object_not_data!(unsafe DispatchGroup);
1818

1919
impl DispatchGroup {
2020
/// Submit a function to a [`DispatchQueue`] and associates it with the [`DispatchGroup`].
21+
#[inline]
2122
pub fn exec_async<F>(&self, queue: &DispatchQueue, work: F)
2223
where
2324
// We need `'static` to make sure any referenced values are borrowed for
@@ -35,6 +36,7 @@ impl DispatchGroup {
3536
/// # Errors
3637
///
3738
/// Return [WaitError::Timeout] in case of timeout.
39+
#[inline]
3840
pub fn wait(&self, timeout: DispatchTime) -> Result<(), WaitError> {
3941
let result = dispatch_group_wait(self, timeout);
4042

@@ -45,6 +47,7 @@ impl DispatchGroup {
4547
}
4648

4749
/// Schedule a function to be submitted to a [`DispatchQueue`] when a group of previously submitted functions have completed.
50+
#[inline]
4851
pub fn notify<F>(&self, queue: &DispatchQueue, work: F)
4952
where
5053
F: Send + FnOnce(),
@@ -58,6 +61,7 @@ impl DispatchGroup {
5861
}
5962

6063
/// Explicitly indicates that the function has entered the [`DispatchGroup`].
64+
#[inline]
6165
pub fn enter(&self) -> DispatchGroupGuard {
6266
// SAFETY: TODO: Is it a soundness requirement that this is paired with leave?
6367
unsafe { dispatch_group_enter(self) };
@@ -72,13 +76,15 @@ pub struct DispatchGroupGuard(DispatchRetained<DispatchGroup>);
7276

7377
impl DispatchGroupGuard {
7478
/// Explicitly indicate that the function in the [`DispatchGroup`] finished executing.
79+
#[inline]
7580
pub fn leave(self) {
7681
// Drop.
7782
let _ = self;
7883
}
7984
}
8085

8186
impl Drop for DispatchGroupGuard {
87+
#[inline]
8288
fn drop(&mut self) {
8389
// SAFETY: TODO: Is it a soundness requirement that this is paired with enter?
8490
unsafe { DispatchGroup::leave(&self.0) };

crates/dispatch2/src/main_thread_bound.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ unsafe impl<T> Send for MainThreadBound<T> {}
7878
unsafe impl<T> Sync for MainThreadBound<T> {}
7979

8080
impl<T> Drop for MainThreadBound<T> {
81+
#[inline]
8182
fn drop(&mut self) {
8283
if mem::needs_drop::<T>() {
8384
// TODO: Figure out whether we should assume the main thread to be

crates/dispatch2/src/object.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub unsafe trait DispatchObject {
6565
/// This extends the duration in which the object is alive by detaching it
6666
/// from the lifetime information carried by the reference.
6767
#[doc(alias = "dispatch_retain")]
68+
#[inline]
6869
fn retain(&self) -> DispatchRetained<Self> {
6970
let ptr: NonNull<Self> = NonNull::from(self);
7071
// SAFETY:
@@ -80,6 +81,7 @@ pub unsafe trait DispatchObject {
8081
///
8182
/// TODO.
8283
#[doc(alias = "dispatch_get_context")]
84+
#[inline]
8385
fn context(&self) -> *mut c_void {
8486
dispatch_get_context(self.as_raw())
8587
}
@@ -90,6 +92,7 @@ pub unsafe trait DispatchObject {
9092
///
9193
/// TODO.
9294
#[doc(alias = "dispatch_set_context")]
95+
#[inline]
9396
unsafe fn set_context(&self, context: *mut c_void) {
9497
// SAFETY: Upheld by the caller.
9598
unsafe { dispatch_set_context(self.as_raw(), context) }
@@ -101,12 +104,14 @@ pub unsafe trait DispatchObject {
101104
///
102105
/// TODO.
103106
#[doc(alias = "dispatch_set_finalizer_f")]
107+
#[inline]
104108
unsafe fn set_finalizer_f(&self, finalizer: dispatch_function_t) {
105109
// SAFETY: Upheld by the caller.
106110
unsafe { dispatch_set_finalizer_f(self.as_raw(), finalizer) }
107111
}
108112

109113
/// Set the finalizer function for the object.
114+
#[inline]
110115
fn set_finalizer<F>(&self, destructor: F)
111116
where
112117
F: Send + FnOnce(),
@@ -132,6 +137,7 @@ pub unsafe trait DispatchObject {
132137
///
133138
/// - There must not be a cycle in the hierarchy of queues.
134139
#[doc(alias = "dispatch_set_target_queue")]
140+
#[inline]
135141
unsafe fn set_target_queue(&self, queue: &DispatchQueue) {
136142
// SAFETY: `object` and `queue` cannot be null, rest is upheld by caller.
137143
unsafe { dispatch_set_target_queue(self.as_raw(), Some(queue)) };
@@ -142,6 +148,7 @@ pub unsafe trait DispatchObject {
142148
/// # Safety
143149
///
144150
/// - DispatchObject should be a queue or queue source.
151+
#[inline]
145152
unsafe fn set_qos_class_floor(
146153
&self,
147154
qos_class: DispatchQoS,
@@ -158,20 +165,24 @@ pub unsafe trait DispatchObject {
158165
}
159166

160167
/// Activate the object.
168+
#[inline]
161169
fn activate(&self) {
162170
dispatch_activate(self.as_raw());
163171
}
164172

165173
/// Suspend the invocation of functions on the object.
174+
#[inline]
166175
fn suspend(&self) {
167176
dispatch_suspend(self.as_raw());
168177
}
169178

170179
/// Resume the invocation of functions on the object.
180+
#[inline]
171181
fn resume(&self) {
172182
dispatch_resume(self.as_raw());
173183
}
174184

185+
#[inline]
175186
#[doc(hidden)]
176187
fn as_raw(&self) -> NonNull<dispatch_object_s> {
177188
NonNull::from(self).cast()

crates/dispatch2/src/queue.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub enum GlobalQueueIdentifier {
5151

5252
impl GlobalQueueIdentifier {
5353
/// Convert and consume [GlobalQueueIdentifier] into its raw value.
54+
#[inline]
5455
pub fn to_identifier(self) -> isize {
5556
match self {
5657
GlobalQueueIdentifier::Priority(queue_priority) => queue_priority.0 as isize,
@@ -70,13 +71,15 @@ dispatch_object_not_data!(unsafe DispatchQueue);
7071

7172
impl DispatchQueue {
7273
/// Create a new [`DispatchQueue`].
74+
#[inline]
7375
pub fn new(label: &str, queue_attribute: Option<&DispatchQueueAttr>) -> DispatchRetained<Self> {
7476
let label = CString::new(label).expect("Invalid label!");
7577

7678
Self::__new(Some(&label), queue_attribute)
7779
}
7880

7981
/// Create a new [`DispatchQueue`] with a given target [`DispatchQueue`].
82+
#[inline]
8083
pub fn new_with_target(
8184
label: &str,
8285
queue_attribute: Option<&DispatchQueueAttr>,
@@ -89,6 +92,7 @@ impl DispatchQueue {
8992
}
9093

9194
/// Return a system-defined global concurrent [`DispatchQueue`] with the priority derived from [GlobalQueueIdentifier].
95+
#[inline]
9296
pub fn global_queue(identifier: GlobalQueueIdentifier) -> DispatchRetained<Self> {
9397
let raw_identifier = identifier.to_identifier();
9498

@@ -109,6 +113,7 @@ impl DispatchQueue {
109113
}
110114

111115
/// Submit a function for synchronous execution on the [`DispatchQueue`].
116+
#[inline]
112117
pub fn exec_sync<F>(&self, work: F)
113118
where
114119
F: Send + FnOnce(),
@@ -124,6 +129,7 @@ impl DispatchQueue {
124129
}
125130

126131
/// Submit a function for asynchronous execution on the [`DispatchQueue`].
132+
#[inline]
127133
pub fn exec_async<F>(&self, work: F)
128134
where
129135
// We need `'static` to make sure any referenced values are borrowed for
@@ -137,6 +143,7 @@ impl DispatchQueue {
137143
}
138144

139145
/// Enqueue a function for execution at the specified time on the [`DispatchQueue`].
146+
#[inline]
140147
pub fn after<F>(&self, when: DispatchTime, work: F) -> Result<(), QueueAfterError>
141148
where
142149
F: Send + FnOnce(),
@@ -150,6 +157,7 @@ impl DispatchQueue {
150157
}
151158

152159
/// Enqueue a barrier function for asynchronous execution on the [`DispatchQueue`] and return immediately.
160+
#[inline]
153161
pub fn barrier_async<F>(&self, work: F)
154162
where
155163
// We need `'static` to make sure any referenced values are borrowed for
@@ -163,6 +171,7 @@ impl DispatchQueue {
163171
}
164172

165173
/// Enqueue a barrier function for synchronous execution on the [`DispatchQueue`] and wait until that function completes.
174+
#[inline]
166175
pub fn barrier_sync<F>(&self, work: F)
167176
where
168177
F: Send + FnOnce(),
@@ -174,6 +183,7 @@ impl DispatchQueue {
174183
}
175184

176185
/// Submit a function for synchronous execution and mark the function as a barrier for subsequent concurrent tasks.
186+
#[inline]
177187
pub fn barrier_async_and_wait<F>(&self, work: F)
178188
where
179189
// We need `'static` to make sure any referenced values are borrowed for
@@ -187,6 +197,7 @@ impl DispatchQueue {
187197
}
188198

189199
/// Sets a function at the given key that will be executed at [`DispatchQueue`] destruction.
200+
#[inline]
190201
pub fn set_specific<F>(&self, key: NonNull<()>, destructor: F)
191202
where
192203
F: Send + FnOnce(),
@@ -204,6 +215,7 @@ impl DispatchQueue {
204215
}
205216

206217
/// Set the QOS class floor of the [`DispatchQueue`].
218+
#[inline]
207219
pub fn set_qos_class_floor(
208220
&self,
209221
qos_class: DispatchQoS,
@@ -248,13 +260,15 @@ impl DispatchQueueAttr {
248260
// };
249261

250262
/// A dispatch queue that executes blocks concurrently.
263+
#[inline]
251264
pub fn concurrent() -> Option<&'static Self> {
252265
// SAFETY: Queues are
253266
unsafe { Some(&_dispatch_queue_attr_concurrent) }
254267
}
255268
}
256269

257270
/// Executes blocks submitted to the main queue.
271+
#[inline]
258272
pub fn dispatch_main() -> ! {
259273
extern "C" {
260274
// `dispatch_main` is marked DISPATCH_NOTHROW.

crates/dispatch2/src/semaphore.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ impl DispatchSemaphore {
2121
/// Return [WaitError::TimeOverflow] if the passed ``timeout`` is too big.
2222
///
2323
/// Return [WaitError::Timeout] in case of timeout.
24+
#[inline]
2425
pub fn try_acquire(&self, timeout: DispatchTime) -> Result<DispatchSemaphoreGuard, WaitError> {
2526
// Safety: DispatchSemaphore cannot be null.
2627
let result = Self::wait(self, timeout);
@@ -44,6 +45,7 @@ pub struct DispatchSemaphoreGuard(ManuallyDrop<DispatchRetained<DispatchSemaphor
4445

4546
impl DispatchSemaphoreGuard {
4647
/// Release the [`DispatchSemaphore`].
48+
#[inline]
4749
pub fn release(self) -> bool {
4850
// We suppress `Drop` for the guard because that would signal the semaphore again.
4951
// The inner `DispatchRetained` is wrapped in `ManuallyDrop` so that it can be
@@ -56,6 +58,7 @@ impl DispatchSemaphoreGuard {
5658
}
5759

5860
impl Drop for DispatchSemaphoreGuard {
61+
#[inline]
5962
fn drop(&mut self) {
6063
// SAFETY: The guard is being dropped; the `ManuallyDrop` contents will not be used again.
6164
let semaphore = unsafe { ManuallyDrop::take(&mut self.0) };

crates/dispatch2/src/time.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ impl DispatchTime {
3939
impl TryFrom<Duration> for DispatchTime {
4040
type Error = ();
4141

42+
#[inline]
4243
fn try_from(value: Duration) -> Result<Self, Self::Error> {
4344
let secs = value.as_secs() as i64;
4445

45-
secs.checked_mul(1_000_000_000)
46+
let delta = secs
47+
.checked_mul(1_000_000_000)
4648
.and_then(|x| x.checked_add(i64::from(value.subsec_nanos())))
47-
.map(|delta| {
48-
// delta cannot overflow
49-
Self::NOW.time(delta)
50-
})
51-
.ok_or(())
49+
.ok_or(())?;
50+
// delta cannot overflow
51+
Ok(Self::NOW.time(delta))
5252
}
5353
}
5454

crates/dispatch2/src/workloop.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ dispatch_object_not_data!(unsafe DispatchWorkloop);
1414

1515
impl DispatchWorkloop {
1616
/// Create a new [`DispatchWorkloop`].
17+
#[inline]
1718
pub fn new(label: &str, inactive: bool) -> DispatchRetained<Self> {
1819
let label = CString::new(label).expect("Invalid label!");
1920

0 commit comments

Comments
 (0)