1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
use super::{
super::{DispatchAutoreleaseFrequency, DispatchQos, DispatchQosClass},
dispatch_queue_attr_t, DispatchQueue, DispatchQueueAttributes,
};
use crate::core::Arc;
use std::{
ffi::CStr,
os::raw::{c_char, c_int, c_ulong},
ptr,
};
/// Configures and creates a [`DispatchQueue`].
#[must_use = "This does nothing until `build` is called"]
#[derive(Clone, Copy)]
pub struct DispatchQueueBuilder<'a> {
qos: DispatchQos,
attr: DispatchQueueAttributes,
autorelease_frequency: DispatchAutoreleaseFrequency,
target: Option<&'a DispatchQueue>,
label: Option<&'a CStr>,
}
impl Default for DispatchQueueBuilder<'_> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl DispatchQueueBuilder<'_> {
/// Creates a [`DispatchQueue`] builder.
#[inline]
pub const fn new() -> Self {
Self {
qos: DispatchQos::UNSPECIFIED,
attr: DispatchQueueAttributes::SERIAL,
autorelease_frequency: DispatchAutoreleaseFrequency::Inherit,
target: None,
label: None,
}
}
/// Creates a new [`DispatchQueue`] with the configuration specified by this
/// builder.
#[inline]
#[doc(alias = "dispatch_queue_create")]
#[doc(alias = "dispatch_queue_create_with_target")]
pub fn build(&self) -> Arc<DispatchQueue> {
extern "C" {
// fn dispatch_queue_create(
// label: *const c_char,
// attr: dispatch_queue_attr_t,
// ) -> dispatch_queue_t;
// available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0)
//
// TODO: Handle availability. Call `dispatch_queue_create` if this
// is unavailable
fn dispatch_queue_create_with_target(
label: *const c_char,
attr: dispatch_queue_attr_t,
target: *const DispatchQueue,
) -> Arc<DispatchQueue>;
// available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0)
//
// TODO: Handle availability.
fn dispatch_queue_attr_make_with_autorelease_frequency(
attr: dispatch_queue_attr_t,
frequency: c_ulong,
) -> dispatch_queue_attr_t;
// available(macOS 10.10, iOS 8.0)
//
// TODO: Handle availability.
fn dispatch_queue_attr_make_with_qos_class(
attr: dispatch_queue_attr_t,
qos_class: DispatchQosClass,
relative_priority: c_int,
) -> dispatch_queue_attr_t;
}
// TODO: Determine if retain/release is needed for
// `dispatch_queue_attr_t` here.
let mut attr = self.attr._to_raw();
if self.autorelease_frequency != DispatchAutoreleaseFrequency::Inherit {
unsafe {
attr = dispatch_queue_attr_make_with_autorelease_frequency(
attr,
self.autorelease_frequency as c_ulong,
);
}
}
if self.qos != DispatchQos::UNSPECIFIED {
unsafe {
attr = dispatch_queue_attr_make_with_qos_class(
attr,
self.qos.qos_class,
self.qos.relative_priority,
);
}
}
let label = match self.label {
Some(label) => label.as_ptr(),
None => ptr::null(),
};
let target = match self.target {
Some(target) => target,
None => ptr::null(),
};
unsafe { dispatch_queue_create_with_target(label, attr, target) }
}
}
/// Configuring the dispatch queue.
impl<'a> DispatchQueueBuilder<'a> {
/// Sets the queue's quality-of-service (QoS), or execution priority.
///
/// The value of `qos.relative_priority` is clamped between `0` and `-15`
/// (`QOS_MIN_RELATIVE_PRIORITY`).
///
/// Default value: [`DispatchQos::UNSPECIFIED`].
#[inline]
pub const fn qos(self, qos: DispatchQos) -> Self {
// `relative_priority` method handles clamping.
self.qos_class(qos.qos_class)
.relative_priority(qos.relative_priority)
}
/// Sets the queue's quality-of-service (QoS) class.
///
/// Default value: [`DispatchQosClass::Unspecified`].
#[inline]
pub const fn qos_class(mut self, qos_class: DispatchQosClass) -> Self {
self.qos.qos_class = qos_class;
self
}
/// Sets the queue's quality-of-service (QoS) relative priority.
///
/// The value is clamped between `0` and `-15`
/// (`QOS_MIN_RELATIVE_PRIORITY`).
///
/// Default value: `0`.
#[inline]
pub const fn relative_priority(mut self, relative_priority: i32) -> Self {
// The value must be clamped or else
// `dispatch_queue_attr_make_with_qos_class` returns null.
const QOS_MIN_RELATIVE_PRIORITY: i32 = -15;
self.qos.relative_priority = if relative_priority > 0 {
0
} else if relative_priority < QOS_MIN_RELATIVE_PRIORITY {
QOS_MIN_RELATIVE_PRIORITY
} else {
relative_priority
};
self
}
/// Sets the attributes that define the behavior of the queue.
///
/// Default value: [`DispatchQueueAttributes::SERIAL`].
#[inline]
pub const fn attr(mut self, attr: DispatchQueueAttributes) -> Self {
self.attr = attr;
self
}
/// Sets the frequency with which the queue creates autorelease pools for
/// its tasks.
///
/// Default value: [`DispatchAutoreleaseFrequency::Inherit`].
#[inline]
pub const fn autorelease_frequency(
mut self,
autorelease_frequency: DispatchAutoreleaseFrequency,
) -> Self {
self.autorelease_frequency = autorelease_frequency;
self
}
/// Sets a target queue to which all blocks are redirected, while keeping
/// the semantics of the created queue.
///
/// See "Dispatch queues" in
/// [`dispatch_set_target_queue`](https://developer.apple.com/documentation/dispatch/1452989-dispatch_set_target_queue)
/// for details.
///
/// Default value: `None`.
#[inline]
pub fn target(mut self, target: &'a DispatchQueue) -> Self {
self.target = Some(target);
self
}
/// Sets a string label to attach to the queue to uniquely identify it in
/// debugging tools such as Instruments, `sample`, stackshots, and crash
/// reports.
///
/// Because applications, libraries, and frameworks can all create their own
/// dispatch queues, a reverse-DNS naming style (`com.example.myqueue`) is
/// recommended.
///
/// Default value: `None`.
#[inline]
pub const fn label(mut self, label: &'a CStr) -> Self {
self.label = Some(label);
self
}
}