Skip to main content

apple_cf/
dispatch_queue.rs

1//! Dispatch Queue wrapper for custom queue management
2//!
3//! This module provides a safe Rust wrapper around GCD (Grand Central Dispatch) queues
4//! that can be used with `ScreenCaptureKit` streams.
5//!
6//! ## When to Use Custom Queues
7//!
8//! By default, stream output handlers are called on a system-managed queue. Use a custom
9//! queue when you need:
10//!
11//! - **Priority control** - Use `UserInteractive` `QoS` for low-latency UI updates
12//! - **Thread isolation** - Ensure handlers run on a specific queue
13//! - **Performance tuning** - Adjust queue priority based on your app's needs
14//!
15//! ## Example
16//!
17//! ```rust,no_run
18//! use apple_cf::dispatch_queue::{DispatchQueue, DispatchQoS};
19//!
20//! // Create a high-priority queue for frame processing
21//! let queue = DispatchQueue::new("com.myapp.capture", DispatchQoS::UserInteractive);
22//! // Pass `queue.as_ptr()` into any framework that accepts a `dispatch_queue_t`.
23//! ```
24
25use std::ffi::{c_void, CString};
26use std::fmt;
27
28/// Quality of Service levels for dispatch queues
29///
30/// These `QoS` levels help the system prioritize work appropriately.
31///
32/// # Examples
33///
34/// ```
35/// use apple_cf::dispatch_queue::{DispatchQueue, DispatchQoS};
36///
37/// // High priority for UI-affecting work
38/// let queue = DispatchQueue::new("com.myapp.ui", DispatchQoS::UserInteractive);
39///
40/// // Lower priority for background tasks
41/// let bg_queue = DispatchQueue::new("com.myapp.background", DispatchQoS::Background);
42/// ```
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
44pub enum DispatchQoS {
45    /// Background `QoS` - for maintenance or cleanup tasks
46    Background = 0,
47    /// Utility `QoS` - for tasks that may take some time
48    Utility = 1,
49    /// Default `QoS` - standard priority
50    #[default]
51    Default = 2,
52    /// User Initiated `QoS` - for tasks initiated by the user
53    UserInitiated = 3,
54    /// User Interactive `QoS` - for tasks that affect the UI
55    UserInteractive = 4,
56}
57
58/// A wrapper around GCD `DispatchQueue`
59///
60/// This allows you to provide a custom dispatch queue for stream output handling
61/// instead of using the default queue.
62///
63/// # Example
64///
65/// ```no_run
66/// use apple_cf::dispatch_queue::{DispatchQueue, DispatchQoS};
67///
68/// let queue = DispatchQueue::new("com.myapp.capture", DispatchQoS::UserInteractive);
69/// ```
70pub struct DispatchQueue {
71    ptr: *const c_void,
72}
73
74unsafe impl Send for DispatchQueue {}
75unsafe impl Sync for DispatchQueue {}
76
77impl DispatchQueue {
78    /// Creates a new dispatch queue with the specified label and `QoS`
79    ///
80    /// # Arguments
81    ///
82    /// * `label` - A string label for the queue (e.g., "com.myapp.capture")
83    /// * `qos` - The quality of service level for the queue
84    ///
85    /// # Examples
86    ///
87    /// ```
88    /// use apple_cf::dispatch_queue::{DispatchQueue, DispatchQoS};
89    ///
90    /// let queue = DispatchQueue::new("com.myapp.capture", DispatchQoS::UserInteractive);
91    /// // Use the queue with SCStream's add_output_handler_with_queue
92    /// ```
93    ///
94    /// # Panics
95    ///
96    /// Panics if the label contains null bytes or if queue creation fails
97    #[must_use] 
98    pub fn new(label: &str, qos: DispatchQoS) -> Self {
99        let c_label = CString::new(label).expect("Label contains null byte");
100        let ptr = unsafe { crate::ffi::dispatch_queue_create(c_label.as_ptr(), qos as i32) };
101        assert!(!ptr.is_null(), "Failed to create dispatch queue");
102        Self { ptr }
103    }
104
105    /// Returns the raw pointer to the dispatch queue
106    ///
107    /// This is used internally for FFI calls (and for testing)
108    #[must_use] 
109    pub const fn as_ptr(&self) -> *const c_void {
110        self.ptr
111    }
112}
113
114impl Clone for DispatchQueue {
115    fn clone(&self) -> Self {
116        unsafe {
117            Self {
118                ptr: crate::ffi::dispatch_queue_retain(self.ptr),
119            }
120        }
121    }
122}
123
124impl Drop for DispatchQueue {
125    fn drop(&mut self) {
126        unsafe {
127            crate::ffi::dispatch_queue_release(self.ptr);
128        }
129    }
130}
131
132impl fmt::Debug for DispatchQueue {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        f.debug_struct("DispatchQueue")
135            .field("ptr", &self.ptr)
136            .finish()
137    }
138}
139
140impl fmt::Display for DispatchQueue {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        write!(f, "DispatchQueue")
143    }
144}