libobs_wrapper\data/
immutable.rs

1use std::{ffi::CStr, sync::Arc};
2
3use libobs::obs_data_t;
4
5use crate::{
6    data::{ObsDataGetters, ObsDataPointers},
7    run_with_obs,
8    runtime::ObsRuntime,
9    unsafe_send::{Sendable, SmartPointerSendable},
10    utils::ObsError,
11};
12
13use super::{ObsData, _ObsDataDropGuard};
14
15#[derive(Clone, Debug)]
16/// Immutable wrapper around obs_data_t to be prevent modification and to be used in creation of other objects.
17///
18/// **DO NOT** update this data using the pointer directly. If you want to change the data,
19/// use the corresponding update methods of the struct you want to update or turn this struct into
20/// a `ObsData` object by using the `to_mutable` method.
21pub struct ImmutableObsData {
22    runtime: ObsRuntime,
23    ptr: SmartPointerSendable<*mut obs_data_t>,
24}
25
26impl ImmutableObsData {
27    pub fn new(runtime: &ObsRuntime) -> Result<Self, ObsError> {
28        let ptr = run_with_obs!(runtime, move || unsafe {
29            // Safety: We are in the runtime, so creating new obs_data_t is safe.
30            Sendable(libobs::obs_data_create())
31        })?;
32
33        let drop_guard = Arc::new(_ObsDataDropGuard {
34            data_ptr: ptr.clone(),
35            runtime: runtime.clone(),
36        });
37
38        let ptr = SmartPointerSendable::new(ptr.0, drop_guard);
39        Ok(ImmutableObsData {
40            ptr,
41            runtime: runtime.clone(),
42        })
43    }
44
45    pub fn from_raw_pointer(data: Sendable<*mut obs_data_t>, runtime: ObsRuntime) -> Self {
46        ImmutableObsData {
47            ptr: SmartPointerSendable::new(
48                data.0,
49                Arc::new(_ObsDataDropGuard {
50                    data_ptr: data.clone(),
51                    runtime: runtime.clone(),
52                }),
53            ),
54            runtime,
55        }
56    }
57
58    pub fn to_mutable(&self) -> Result<ObsData, ObsError> {
59        let ptr = self.ptr.clone();
60        let json = run_with_obs!(self.runtime, (ptr), move || {
61            let json_ptr = unsafe {
62                // Safety: We are making sure by using a SmartPointer, that this pointer is valid during the call.
63                libobs::obs_data_get_json(ptr.get_ptr())
64            };
65
66            if json_ptr.is_null() {
67                return Err(ObsError::NullPointer(Some(
68                    "Couldn't get json representation of OBS data".into(),
69                )));
70            }
71
72            let json = unsafe {
73                // Safety: We made sure the json ptr is valid because it is not null.
74                CStr::from_ptr(json_ptr)
75            }
76            .to_str()
77            .map_err(|_| ObsError::JsonParseError)?
78            .to_string();
79
80            Ok(json)
81        })??;
82
83        ObsData::from_json(json.as_ref(), self.runtime.clone())
84    }
85}
86
87impl ObsDataPointers for ImmutableObsData {
88    fn runtime(&self) -> &ObsRuntime {
89        &self.runtime
90    }
91
92    fn as_ptr(&self) -> SmartPointerSendable<*mut obs_data_t> {
93        self.ptr.clone()
94    }
95}
96
97impl ObsDataGetters for ImmutableObsData {}
98
99impl From<ObsData> for ImmutableObsData {
100    fn from(data: ObsData) -> Self {
101        ImmutableObsData {
102            ptr: data.as_ptr(),
103            runtime: data.runtime.clone(),
104        }
105    }
106}