use core::ffi::{c_uint, c_void};
use core::ptr::NonNull;
use alloc::boxed::Box;
use crate::dispatch_function_t;
use crate::generated::dispatch_get_context;
use crate::{
generated::{
dispatch_activate, dispatch_resume, dispatch_set_context, dispatch_set_finalizer_f,
dispatch_set_qos_class_floor, dispatch_set_target_queue, dispatch_suspend,
},
DispatchRetained,
};
use super::{utils::function_wrapper, DispatchQueue};
enum_with_val! {
#[doc(alias = "dispatch_qos_class_t")]
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct DispatchQoS(pub c_uint) {
#[doc(alias = "QOS_CLASS_USER_INTERACTIVE")]
UserInteractive = 0x21,
#[doc(alias = "QOS_CLASS_USER_INITIATED")]
UserInitiated = 0x19,
#[doc(alias = "QOS_CLASS_DEFAULT")]
Default = 0x15,
#[doc(alias = "QOS_CLASS_UTILITY")]
Utility = 0x11,
#[doc(alias = "QOS_CLASS_BACKGROUND")]
Background = 0x09,
#[doc(alias = "QOS_CLASS_UNSPECIFIED")]
Unspecified = 0x00,
}
}
#[allow(missing_docs)] pub const QOS_MIN_RELATIVE_PRIORITY: i32 = -15;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum QualityOfServiceClassFloorError {
InvalidRelativePriority,
}
#[doc(alias = "dispatch_object_t")]
pub unsafe trait DispatchObject {
#[doc(alias = "dispatch_retain")]
fn retain(&self) -> DispatchRetained<Self> {
let ptr: NonNull<Self> = NonNull::from(self);
unsafe { DispatchRetained::retain(ptr) }
}
#[doc(alias = "dispatch_get_context")]
fn context(&self) -> *mut c_void {
dispatch_get_context(self.as_raw())
}
#[doc(alias = "dispatch_set_context")]
unsafe fn set_context(&self, context: *mut c_void) {
unsafe { dispatch_set_context(self.as_raw(), context) }
}
#[doc(alias = "dispatch_set_finalizer_f")]
unsafe fn set_finalizer_f(&self, finalizer: dispatch_function_t) {
unsafe { dispatch_set_finalizer_f(self.as_raw(), finalizer) }
}
fn set_finalizer<F>(&self, destructor: F)
where
F: Send + FnOnce(),
{
let destructor_boxed = Box::into_raw(Box::new(destructor)).cast();
unsafe {
self.set_context(destructor_boxed);
self.set_finalizer_f(function_wrapper::<F>)
}
}
#[doc(alias = "dispatch_set_target_queue")]
unsafe fn set_target_queue(&self, queue: &DispatchQueue) {
unsafe { dispatch_set_target_queue(self.as_raw(), Some(queue)) };
}
unsafe fn set_qos_class_floor(
&self,
qos_class: DispatchQoS,
relative_priority: i32,
) -> Result<(), QualityOfServiceClassFloorError> {
if !(QOS_MIN_RELATIVE_PRIORITY..=0).contains(&relative_priority) {
return Err(QualityOfServiceClassFloorError::InvalidRelativePriority);
}
unsafe { dispatch_set_qos_class_floor(self.as_raw(), qos_class, relative_priority) };
Ok(())
}
fn activate(&self) {
dispatch_activate(self.as_raw());
}
fn suspend(&self) {
dispatch_suspend(self.as_raw());
}
fn resume(&self) {
dispatch_resume(self.as_raw());
}
#[doc(hidden)]
fn as_raw(&self) -> NonNull<dispatch_object_s> {
NonNull::from(self).cast()
}
}
mod private {
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug)]
pub struct dispatch_object_s {
_inner: [u8; 0],
_p: crate::OpaqueData,
}
#[cfg(feature = "objc2")]
unsafe impl objc2::encode::RefEncode for dispatch_object_s {
const ENCODING_REF: objc2::encode::Encoding = objc2::encode::Encoding::Object;
}
}
pub(crate) use private::dispatch_object_s;