1use core::ffi::{c_uint, c_void};
2use core::ptr::NonNull;
3
4use alloc::boxed::Box;
5
6use crate::dispatch_function_t;
7use crate::generated::dispatch_get_context;
8use crate::{
9 generated::{
10 dispatch_activate, dispatch_resume, dispatch_set_context, dispatch_set_finalizer_f,
11 dispatch_set_qos_class_floor, dispatch_set_target_queue, dispatch_suspend,
12 },
13 DispatchRetained,
14};
15
16use super::{utils::function_wrapper, DispatchQueue};
17
18enum_with_val! {
19 #[doc(alias = "dispatch_qos_class_t")]
21 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
22 pub struct DispatchQoS(pub c_uint) {
23 #[doc(alias = "QOS_CLASS_USER_INTERACTIVE")]
25 UserInteractive = 0x21,
26 #[doc(alias = "QOS_CLASS_USER_INITIATED")]
28 UserInitiated = 0x19,
29 #[doc(alias = "QOS_CLASS_DEFAULT")]
31 Default = 0x15,
32 #[doc(alias = "QOS_CLASS_UTILITY")]
34 Utility = 0x11,
35 #[doc(alias = "QOS_CLASS_BACKGROUND")]
37 Background = 0x09,
38 #[doc(alias = "QOS_CLASS_UNSPECIFIED")]
40 Unspecified = 0x00,
41 }
42}
43
44#[allow(missing_docs)] pub const QOS_MIN_RELATIVE_PRIORITY: i32 = -15;
46
47#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
49#[non_exhaustive]
50pub enum QualityOfServiceClassFloorError {
51 InvalidRelativePriority,
53}
54
55#[doc(alias = "dispatch_object_t")]
62pub unsafe trait DispatchObject {
63 #[doc(alias = "dispatch_retain")]
68 #[inline]
69 fn retain(&self) -> DispatchRetained<Self> {
70 let ptr: NonNull<Self> = NonNull::from(self);
71 unsafe { DispatchRetained::retain(ptr) }
76 }
77
78 #[doc(alias = "dispatch_get_context")]
84 #[inline]
85 fn context(&self) -> *mut c_void {
86 dispatch_get_context(self.as_raw())
87 }
88
89 #[doc(alias = "dispatch_set_context")]
95 #[inline]
96 unsafe fn set_context(&self, context: *mut c_void) {
97 unsafe { dispatch_set_context(self.as_raw(), context) }
99 }
100
101 #[doc(alias = "dispatch_set_finalizer_f")]
107 #[inline]
108 unsafe fn set_finalizer_f(&self, finalizer: dispatch_function_t) {
109 unsafe { dispatch_set_finalizer_f(self.as_raw(), finalizer) }
111 }
112
113 #[inline]
115 fn set_finalizer<F>(&self, destructor: F)
116 where
117 F: Send + FnOnce(),
118 {
119 let destructor_boxed = Box::into_raw(Box::new(destructor)).cast();
120
121 unsafe {
125 self.set_context(destructor_boxed);
126 self.set_finalizer_f(function_wrapper::<F>)
127 }
128 }
129
130 #[doc(alias = "dispatch_set_target_queue")]
140 #[inline]
141 unsafe fn set_target_queue(&self, queue: &DispatchQueue) {
142 unsafe { dispatch_set_target_queue(self.as_raw(), Some(queue)) };
144 }
145
146 #[inline]
152 unsafe fn set_qos_class_floor(
153 &self,
154 qos_class: DispatchQoS,
155 relative_priority: i32,
156 ) -> Result<(), QualityOfServiceClassFloorError> {
157 if !(QOS_MIN_RELATIVE_PRIORITY..=0).contains(&relative_priority) {
158 return Err(QualityOfServiceClassFloorError::InvalidRelativePriority);
159 }
160
161 unsafe { dispatch_set_qos_class_floor(self.as_raw(), qos_class, relative_priority) };
163
164 Ok(())
165 }
166
167 #[inline]
169 fn activate(&self) {
170 dispatch_activate(self.as_raw());
171 }
172
173 #[inline]
175 fn suspend(&self) {
176 dispatch_suspend(self.as_raw());
177 }
178
179 #[inline]
181 fn resume(&self) {
182 dispatch_resume(self.as_raw());
183 }
184
185 #[inline]
186 #[doc(hidden)]
187 fn as_raw(&self) -> NonNull<dispatch_object_s> {
188 NonNull::from(self).cast()
189 }
190}
191
192mod private {
198 #[allow(non_camel_case_types)]
199 #[repr(C)]
200 #[derive(Debug)]
201 pub struct dispatch_object_s {
202 _inner: [u8; 0],
204 _p: crate::OpaqueData,
205 }
206
207 #[cfg(feature = "objc2")]
208 unsafe impl objc2::encode::RefEncode for dispatch_object_s {
210 const ENCODING_REF: objc2::encode::Encoding = objc2::encode::Encoding::Object;
211 }
212}
213
214pub(crate) use private::dispatch_object_s;