libobs_wrapper\data/
mod.rs

1//! This module contains every struct related to storing data in OBS.
2//! There are two important structs:
3//! 1. `ObsData`
4//! - This struct holds a mutable reference to a ObsData, so you can set a string, ints and similar
5//! - You can convert this ObsData object to a immutable reference
6//! - Cloning this ObsData struct is very memory intensive, as the ObsData will completely clone every member of this data.
7//! 2. `ImmutableObsData`
8//! - This structs holds, as the name might suggest, an immutable reference to ObsData.
9//! - The data inside this struct can not be changed and is intended for read-only.
10//! - You can turn this ImmutableObsData into a writable `ObsData` struct again, but this will internally clone the data and not affect the `ImmutableObsData` itself.
11use std::{ffi::CString, sync::Arc};
12
13use crate::{
14    impl_obs_drop, run_with_obs,
15    runtime::ObsRuntime,
16    unsafe_send::{Sendable, SmartPointerSendable},
17    utils::{ObsDropGuard, ObsError},
18};
19pub use immutable::ImmutableObsData;
20
21pub mod audio;
22mod immutable;
23mod lib_support;
24pub mod object;
25pub mod output;
26pub mod properties;
27pub mod video;
28pub use lib_support::*;
29mod updater;
30pub use updater::*;
31mod traits;
32pub use traits::*;
33
34#[derive(Debug)]
35pub(super) struct _ObsDataDropGuard {
36    data_ptr: Sendable<*mut libobs::obs_data_t>,
37    runtime: ObsRuntime,
38}
39
40impl_obs_drop!(_ObsDataDropGuard, (data_ptr), move || unsafe {
41    // Safety: This is the drop guard, so the data_ptr must be valid here.
42    libobs::obs_data_release(data_ptr.0)
43});
44
45impl ObsDropGuard for _ObsDataDropGuard {}
46
47/// Contains `obs_data` and its related strings. Note that
48/// this struct prevents string pointers from being freed
49/// by keeping them owned.
50/// Cloning `ObsData` is blocking and will create a new `ObsData` instance. Recommended is to use `ObsData::full_clone()` instead.
51/// ## Panics
52/// If the underlying JSON representation can not be parsed.
53//NOTE: Update: The strings are actually copied by obs itself, we don't need to store them
54#[derive(Debug)]
55pub struct ObsData {
56    pub(crate) runtime: ObsRuntime,
57    ptr: SmartPointerSendable<*mut libobs::obs_data_t>,
58}
59
60impl ObsData {
61    /// Creates a new empty `ObsData` wrapper for the
62    /// libobs `obs_data` data structure.
63    ///
64    /// `ObsData` can then be populated using the set
65    /// functions, which take ownership of the
66    /// `ObsString` types to prevent them from being
67    /// dropped prematurely. This makes it safer than
68    /// using `obs_data` directly from libobs.
69    pub fn new(runtime: ObsRuntime) -> Result<Self, ObsError> {
70        let obs_data = run_with_obs!(runtime, move || unsafe {
71            // Safety: We are in the runtime, so creating new obs_data_t is safe.
72            Sendable(libobs::obs_data_create())
73        })?;
74
75        let drop_guard = Arc::new(_ObsDataDropGuard {
76            data_ptr: obs_data.clone(),
77            runtime: runtime.clone(),
78        });
79        let ptr = SmartPointerSendable::new(obs_data.0, drop_guard.clone());
80        Ok(ObsData {
81            ptr,
82            runtime: runtime.clone(),
83        })
84    }
85
86    pub fn bulk_update(&mut self) -> ObsDataUpdater {
87        ObsDataUpdater::new(self.as_ptr(), self.runtime.clone())
88    }
89
90    pub fn from_json(json: &str, runtime: ObsRuntime) -> Result<Self, ObsError> {
91        let cstr = CString::new(json).map_err(|_| ObsError::JsonParseError)?;
92
93        let raw_ptr = run_with_obs!(runtime, (cstr), move || unsafe {
94            // Safety: We made sure that the cstr pointer is valid during the call.
95            Sendable(libobs::obs_data_create_from_json(cstr.as_ptr()))
96        })?;
97
98        if raw_ptr.0.is_null() {
99            return Err(ObsError::JsonParseError);
100        }
101
102        let drop_guard = Arc::new(_ObsDataDropGuard {
103            data_ptr: raw_ptr.clone(),
104            runtime: runtime.clone(),
105        });
106
107        let ptr = SmartPointerSendable::new(raw_ptr.0, drop_guard.clone());
108
109        Ok(ObsData {
110            ptr,
111            runtime: runtime.clone(),
112        })
113    }
114
115    /// Converts this `ObsData` into an `ImmutableObsData`.
116    /// Transfers the pointer without cloning.
117    pub fn into_immutable(self) -> ImmutableObsData {
118        ImmutableObsData::from(self)
119    }
120}
121
122impl ObsDataPointers for ObsData {
123    fn runtime(&self) -> &ObsRuntime {
124        &self.runtime
125    }
126
127    fn as_ptr(&self) -> SmartPointerSendable<*mut libobs::obs_data_t> {
128        self.ptr.clone()
129    }
130}
131
132impl ObsDataGetters for ObsData {}
133impl ObsDataSetters for ObsData {}
134
135impl Clone for ObsData {
136    fn clone(&self) -> Self {
137        let json = self.get_json().unwrap();
138        Self::from_json(json.as_str(), self.runtime.clone()).unwrap()
139    }
140}