libobs_wrapper\data/
mod.rs

1use std::{ffi::CString, sync::Arc};
2
3use crate::{
4    impl_obs_drop, run_with_obs,
5    runtime::ObsRuntime,
6    unsafe_send::Sendable,
7    utils::{ObsError, ObsString},
8};
9use libobs::obs_data;
10
11pub mod audio;
12pub mod immutable;
13mod lib_support;
14pub mod output;
15pub mod properties;
16pub mod video;
17pub use lib_support::*;
18mod updater;
19pub use updater::*;
20mod traits;
21pub use traits::*;
22
23#[derive(Debug)]
24pub(crate) struct _ObsDataDropGuard {
25    obs_data: Sendable<*mut obs_data>,
26    pub(crate) runtime: ObsRuntime,
27}
28
29/// Contains `obs_data` and its related strings. Note that
30/// this struct prevents string pointers from being freed
31/// by keeping them owned.
32/// Cloning `ObsData` is blocking and will create a new `ObsData` instance. Recommended is to use `ObsData::full_clone()` instead.
33/// ## Panics
34/// If the underlying JSON representation can not be parsed.
35//NOTE: Update: The strings are actually copied by obs itself, we don't need to store them
36#[derive(Debug)]
37pub struct ObsData {
38    obs_data: Sendable<*mut obs_data>,
39    pub(crate) runtime: ObsRuntime,
40    pub(crate) _drop_guard: Arc<_ObsDataDropGuard>,
41}
42
43impl ObsData {
44    /// Creates a new empty `ObsData` wrapper for the
45    /// libobs `obs_data` data structure.
46    ///
47    /// `ObsData` can then be populated using the set
48    /// functions, which take ownership of the
49    /// `ObsString` types to prevent them from being
50    /// dropped prematurely. This makes it safer than
51    /// using `obs_data` directly from libobs.
52    pub fn new(runtime: ObsRuntime) -> Result<Self, ObsError> {
53        let obs_data = run_with_obs!(runtime, move || unsafe {
54            Sendable(libobs::obs_data_create())
55        })?;
56
57        Ok(ObsData {
58            obs_data: obs_data.clone(),
59            runtime: runtime.clone(),
60            _drop_guard: Arc::new(_ObsDataDropGuard { obs_data, runtime }),
61        })
62    }
63
64    pub fn bulk_update(&mut self) -> ObsDataUpdater {
65        ObsDataUpdater {
66            changes: Vec::new(),
67            obs_data: self.obs_data.clone(),
68            _drop_guard: self._drop_guard.clone(),
69        }
70    }
71
72    /// Returns a pointer to the raw `obs_data`
73    /// represented by `ObsData`.
74    pub fn as_ptr(&self) -> Sendable<*mut obs_data> {
75        self.obs_data.clone()
76    }
77
78    /// Sets a string in `obs_data` and stores it so
79    /// it in `ObsData` does not get freed.
80    pub fn set_string<T: Into<ObsString> + Send + Sync, K: Into<ObsString> + Send + Sync>(
81        &mut self,
82        key: T,
83        value: K,
84    ) -> Result<&mut Self, ObsError> {
85        let key = key.into();
86        let value = value.into();
87
88        let key_ptr = key.as_ptr();
89        let value_ptr = value.as_ptr();
90        let data_ptr = self.obs_data.clone();
91
92        run_with_obs!(
93            self.runtime,
94            (data_ptr, key_ptr, value_ptr),
95            move || unsafe { libobs::obs_data_set_string(data_ptr, key_ptr, value_ptr) }
96        )?;
97
98        Ok(self)
99    }
100
101    /// Sets an int in `obs_data` and stores the key
102    /// in `ObsData` so it does not get freed.
103    pub fn set_int<T: Into<ObsString> + Sync + Send>(
104        &mut self,
105        key: T,
106        value: i64,
107    ) -> Result<&mut Self, ObsError> {
108        let key = key.into();
109
110        let key_ptr = key.as_ptr();
111        let data_ptr = self.obs_data.clone();
112
113        run_with_obs!(self.runtime, (key_ptr, data_ptr), move || unsafe {
114            libobs::obs_data_set_int(data_ptr, key_ptr, value);
115        })?;
116
117        Ok(self)
118    }
119
120    /// Sets a bool in `obs_data` and stores the key
121    /// in `ObsData` so it does not get freed.
122    pub fn set_bool<T: Into<ObsString> + Sync + Send>(
123        &mut self,
124        key: T,
125        value: bool,
126    ) -> Result<&mut Self, ObsError> {
127        let key = key.into();
128
129        let key_ptr = key.as_ptr();
130        let data_ptr = self.obs_data.clone();
131        run_with_obs!(self.runtime, (key_ptr, data_ptr), move || unsafe {
132            libobs::obs_data_set_bool(data_ptr, key_ptr, value);
133        })?;
134
135        Ok(self)
136    }
137
138    /// Sets a double in `obs_data` and stores the key
139    /// in `ObsData` so it does not get freed.
140    pub fn set_double<T: Into<ObsString> + Sync + Send>(
141        &mut self,
142        key: T,
143        value: f64,
144    ) -> Result<&mut Self, ObsError> {
145        let key = key.into();
146
147        let key_ptr = key.as_ptr();
148        let data_ptr = self.obs_data.clone();
149
150        run_with_obs!(self.runtime, (key_ptr, data_ptr), move || unsafe {
151            libobs::obs_data_set_double(data_ptr, key_ptr, value);
152        })?;
153
154        Ok(self)
155    }
156
157    pub fn from_json(json: &str, runtime: ObsRuntime) -> Result<Self, ObsError> {
158        let cstr = CString::new(json).map_err(|_| ObsError::JsonParseError)?;
159
160        let cstr_ptr = Sendable(cstr.as_ptr());
161        let result = run_with_obs!(runtime, (cstr_ptr), move || unsafe {
162            Sendable(libobs::obs_data_create_from_json(cstr_ptr))
163        })?;
164
165        if result.0.is_null() {
166            return Err(ObsError::JsonParseError);
167        }
168
169        Ok(ObsData {
170            obs_data: result.clone(),
171            runtime: runtime.clone(),
172            _drop_guard: Arc::new(_ObsDataDropGuard {
173                obs_data: result,
174                runtime,
175            }),
176        })
177    }
178}
179
180impl_obs_drop!(_ObsDataDropGuard, (obs_data), move || unsafe {
181    libobs::obs_data_release(obs_data)
182});
183
184impl Clone for ObsData {
185    fn clone(&self) -> Self {
186        let json = self.get_json().unwrap();
187        Self::from_json(json.as_str(), self.runtime.clone()).unwrap()
188    }
189}