Skip to main content

screencapturekit/stream/configuration/
internal.rs

1use std::ffi::c_void;
2use std::fmt;
3
4/// Opaque wrapper around `SCStreamConfiguration`
5///
6/// Configuration for a screen capture stream, including dimensions,
7/// pixel format, audio settings, and other capture parameters.
8///
9/// # Examples
10///
11/// ```
12/// use screencapturekit::stream::configuration::SCStreamConfiguration;
13///
14/// let config = SCStreamConfiguration::new()
15///     .with_width(1920)
16///     .with_height(1080);
17/// ```
18#[repr(transparent)]
19pub struct SCStreamConfiguration(pub(crate) *const c_void);
20
21impl PartialEq for SCStreamConfiguration {
22    /// Identity comparison: two `SCStreamConfiguration`s are equal only when
23    /// they wrap the same native object.
24    ///
25    /// Because [`Clone`] deep-copies (see below), `config != config.clone()`
26    /// even though the two carry identical settings.
27    fn eq(&self, other: &Self) -> bool {
28        self.0 == other.0
29    }
30}
31
32impl Eq for SCStreamConfiguration {}
33
34impl std::hash::Hash for SCStreamConfiguration {
35    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
36        self.0.hash(state);
37    }
38}
39
40impl SCStreamConfiguration {
41    pub(crate) fn internal_init() -> Self {
42        unsafe {
43            let ptr = crate::ffi::sc_stream_configuration_create();
44            Self(ptr)
45        }
46    }
47
48    pub(crate) fn as_ptr(&self) -> *const c_void {
49        self.0
50    }
51}
52
53// `Clone::clone` is not a `memcpy`: it crosses the Swift FFI boundary and
54// deep-copies the underlying `SCStreamConfiguration`. That is deliberate.
55// `SCStreamConfiguration` is a *mutable* Objective-C class, so a retain-based
56// clone would hand out aliases: `config.clone().set_width(..)` would silently
57// resize the original, and two threads configuring "their own" clone would
58// race on the same non-atomic properties — which the `Send`/`Sync` impls below
59// promise cannot happen. If you're cloning per frame on a hot path, share an
60// `Arc<SCStreamConfiguration>` (or a `&SCStreamConfiguration`) instead.
61impl Clone for SCStreamConfiguration {
62    fn clone(&self) -> Self {
63        Self(unsafe { crate::ffi::sc_stream_configuration_copy(self.0) })
64    }
65}
66
67crate::utils::retained::sc_retained!(
68    SCStreamConfiguration,
69    release = crate::ffi::sc_stream_configuration_release,
70);
71
72unsafe impl Send for SCStreamConfiguration {}
73unsafe impl Sync for SCStreamConfiguration {}
74
75impl fmt::Debug for SCStreamConfiguration {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        f.debug_struct("SCStreamConfiguration")
78            .field("ptr", &self.0)
79            .finish()
80    }
81}
82
83impl fmt::Display for SCStreamConfiguration {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        write!(f, "SCStreamConfiguration")
86    }
87}