libobs_wrapper\data/
updater.rs

1use std::sync::Arc;
2
3use libobs::{
4    obs_data, obs_data_set_bool, obs_data_set_double, obs_data_set_int, obs_data_set_string,
5};
6
7use crate::{
8    run_with_obs,
9    unsafe_send::Sendable,
10    utils::{ObsError, ObsString},
11};
12
13use super::_ObsDataDropGuard;
14
15#[derive(Debug)]
16pub enum ObsDataChange {
17    String(ObsString, ObsString),
18    Int(ObsString, i64),
19    Bool(ObsString, bool),
20    Double(ObsString, f64),
21}
22
23#[derive(Debug)]
24/// Important: Make sure to call `update()` after setting the values.
25/// This will apply the changes to the `ObsData` object.
26#[must_use = "The `update()` method must be called to apply changes."]
27pub struct ObsDataUpdater {
28    pub(crate) changes: Vec<ObsDataChange>,
29    pub(crate) obs_data: Sendable<*mut obs_data>,
30    pub(crate) _drop_guard: Arc<_ObsDataDropGuard>,
31}
32
33impl ObsDataUpdater {
34    pub fn set_string_ref(&mut self, key: impl Into<ObsString>, value: impl Into<ObsString>) {
35        let key = key.into();
36        let value = value.into();
37
38        log::trace!("Setting string: {:?} = {:?}", key, value);
39        self.changes.push(ObsDataChange::String(key, value));
40    }
41
42    pub fn set_string(mut self, key: impl Into<ObsString>, value: impl Into<ObsString>) -> Self {
43        self.set_string_ref(key, value);
44        self
45    }
46
47    pub fn set_int_ref(&mut self, key: impl Into<ObsString>, value: i64) {
48        let key = key.into();
49        self.changes.push(ObsDataChange::Int(key, value));
50    }
51
52    pub fn set_int(mut self, key: impl Into<ObsString>, value: i64) -> Self {
53        self.set_int_ref(key, value);
54        self
55    }
56
57    pub fn set_bool_ref(&mut self, key: impl Into<ObsString>, value: bool) {
58        let key = key.into();
59        self.changes.push(ObsDataChange::Bool(key, value));
60    }
61
62    pub fn set_bool(mut self, key: impl Into<ObsString>, value: bool) -> Self {
63        self.set_bool_ref(key, value);
64        self
65    }
66
67    #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
68    pub async fn update(self) -> Result<(), ObsError> {
69        let ObsDataUpdater {
70            changes,
71            obs_data,
72            _drop_guard,
73        } = self;
74
75        let obs_data = obs_data.clone();
76        run_with_obs!(_drop_guard.runtime, (obs_data), move || unsafe {
77            for change in changes {
78                match change {
79                    ObsDataChange::String(key, value) => {
80                        obs_data_set_string(obs_data, key.as_ptr().0, value.as_ptr().0)
81                    }
82                    ObsDataChange::Int(key, value) => {
83                        obs_data_set_int(obs_data, key.as_ptr().0, value.into())
84                    }
85                    ObsDataChange::Bool(key, value) => {
86                        obs_data_set_bool(obs_data, key.as_ptr().0, value.into())
87                    }
88                    ObsDataChange::Double(key, value) => {
89                        obs_data_set_double(obs_data, key.as_ptr().0, value)
90                    }
91                };
92            }
93        }).await
94    }
95}