libobs_wrapper\data\traits/
getters.rs

1use std::ffi::CStr;
2
3use crate::{
4    data::ObsDataPointers,
5    run_with_obs,
6    unsafe_send::SmartPointerSendable,
7    utils::{ObsError, ObsString},
8};
9
10/// # Safety
11/// This function must be called on the OBS runtime.
12#[allow(unknown_lints)]
13#[allow(ensure_obs_call_in_runtime)]
14unsafe fn has_value(
15    data_ptr: SmartPointerSendable<*mut libobs::obs_data_t>,
16    key: &ObsString,
17) -> bool {
18    libobs::obs_data_has_user_value(data_ptr.get_ptr(), key.as_ptr().0)
19        || libobs::obs_data_has_default_value(data_ptr.get_ptr(), key.as_ptr().0)
20}
21
22pub trait ObsDataGetters: ObsDataPointers {
23    fn get_string<T: Into<ObsString> + Send + Sync>(
24        &self,
25        key: T,
26    ) -> Result<Option<String>, ObsError> {
27        let key = key.into();
28        let data_ptr = self.as_ptr();
29
30        run_with_obs!(self.runtime(), (data_ptr, key), move || {
31            let has_value = unsafe {
32                // Safety: We are running on the OBS runtime.
33                has_value(data_ptr.clone(), &key)
34            };
35
36            if has_value {
37                let result = unsafe {
38                    // Safety: The pointer is valid because we are using a smart pointer
39                    libobs::obs_data_get_string(data_ptr.get_ptr(), key.as_ptr().0)
40                };
41
42                if result.is_null() {
43                    Err(ObsError::NullPointer(None))
44                } else {
45                    let result = unsafe {
46                        // Safety: The pointer is valid because OBS returned it and we are still in runtime.
47                        CStr::from_ptr(result)
48                    };
49                    let result = result
50                        .to_str()
51                        .map_err(|_| ObsError::StringConversionError)?
52                        .to_string();
53
54                    Ok(Some(result))
55                }
56            } else {
57                Ok(None)
58            }
59        })?
60    }
61    fn get_int<T: Into<ObsString> + Sync + Send>(&self, key: T) -> Result<Option<i64>, ObsError> {
62        let key = key.into();
63        let data_ptr = self.as_ptr();
64
65        run_with_obs!(self.runtime(), (data_ptr, key), move || {
66            let has_value = unsafe {
67                // Safety: We are running on the OBS runtime.
68                has_value(data_ptr.clone(), &key)
69            };
70
71            if has_value {
72                Some(unsafe {
73                    // Safety: The pointer is valid because we are using a smart pointer
74                    libobs::obs_data_get_int(data_ptr.get_ptr(), key.as_ptr().0)
75                })
76            } else {
77                None
78            }
79        })
80    }
81    fn get_bool<T: Into<ObsString> + Sync + Send>(&self, key: T) -> Result<Option<bool>, ObsError> {
82        let key = key.into();
83
84        let data_ptr = self.as_ptr();
85
86        run_with_obs!(self.runtime(), (data_ptr, key), move || {
87            let has_value = unsafe {
88                // Safety: We are running on the OBS runtime.
89                has_value(data_ptr.clone(), &key)
90            };
91
92            if has_value {
93                Some(unsafe {
94                    // Safety: The pointer is valid because we are using a smart pointer
95                    libobs::obs_data_get_bool(data_ptr.get_ptr(), key.as_ptr().0)
96                })
97            } else {
98                None
99            }
100        })
101    }
102    fn get_double<T: Into<ObsString> + Sync + Send>(
103        &self,
104        key: T,
105    ) -> Result<Option<f64>, ObsError> {
106        let key = key.into();
107        let data_ptr = self.as_ptr();
108
109        let result = run_with_obs!(self.runtime(), (key, data_ptr), move || {
110            let has_value = unsafe {
111                // Safety: We are running on the OBS runtime.
112                has_value(data_ptr.clone(), &key)
113            };
114
115            if has_value {
116                Some(unsafe {
117                    // Safety: The pointer is valid because we are using a smart pointer
118                    libobs::obs_data_get_double(data_ptr.get_ptr(), key.as_ptr().0)
119                })
120            } else {
121                None
122            }
123        })?;
124
125        Ok(result)
126    }
127
128    fn get_json(&self) -> Result<String, ObsError> {
129        let data_ptr = self.as_ptr();
130        run_with_obs!(self.runtime(), (data_ptr), move || {
131            let json_ptr = unsafe {
132                // Safety: The pointer is valid because we are using a smart pointer
133                libobs::obs_data_get_json(data_ptr.get_ptr())
134            };
135
136            if json_ptr.is_null() {
137                return Err(ObsError::NullPointer(Some(
138                    "Couldn't get json representation of OBS data".into(),
139                )));
140            }
141
142            let json = unsafe {
143                // Safety: The pointer is valid because OBS returned it and we are still in runtime.
144                CStr::from_ptr(json_ptr)
145            }
146            .to_str()
147            .map_err(|_| ObsError::JsonParseError)?
148            .to_string();
149
150            Ok(json)
151        })?
152    }
153}