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    pub fn new(label: &str, qos: DispatchQoS) -> Self {
98        let c_label = CString::new(label).expect("Label contains null byte");
99        let ptr = unsafe { crate::ffi::dispatch_queue_create(c_label.as_ptr(), qos as i32) };
100        assert!(!ptr.is_null(), "Failed to create dispatch queue");
101        Self { ptr }
102    }
103
104    /// Returns the raw pointer to the dispatch queue
105    ///
106    /// This is used internally for FFI calls (and for testing)
107    pub fn as_ptr(&self) -> *const c_void {
108        self.ptr
109    }
110}
111
112impl Clone for DispatchQueue {
113    fn clone(&self) -> Self {
114        unsafe {
115            Self {
116                ptr: crate::ffi::dispatch_queue_retain(self.ptr),
117            }
118        }
119    }
120}
121
122impl Drop for DispatchQueue {
123    fn drop(&mut self) {
124        unsafe {
125            crate::ffi::dispatch_queue_release(self.ptr);
126        }
127    }
128}
129
130impl fmt::Debug for DispatchQueue {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        f.debug_struct("DispatchQueue")
133            .field("ptr", &self.ptr)
134            .finish()
135    }
136}
137
138impl fmt::Display for DispatchQueue {
139    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140        write!(f, "DispatchQueue")
141    }
142}