orbis_plugin_api/sdk/
state.rs1#[allow(unused_imports)]
21use super::error::{Error, Result};
22use serde::{de::DeserializeOwned, Serialize};
23
24#[cfg(target_arch = "wasm32")]
32pub fn get<T: DeserializeOwned>(key: &str) -> Result<Option<T>> {
33 let ptr = unsafe {
34 super::ffi::state_get(key.as_ptr() as i32, key.len() as i32)
35 };
36
37 if ptr == 0 {
38 return Ok(None);
39 }
40
41 let bytes = unsafe { super::ffi::read_length_prefixed(ptr) };
42 let value: T = serde_json::from_slice(&bytes)?;
43 Ok(Some(value))
44}
45
46#[cfg(not(target_arch = "wasm32"))]
48pub fn get<T: DeserializeOwned>(_key: &str) -> Result<Option<T>> {
49 Ok(None)
50}
51
52#[inline]
60pub fn get_or<T: DeserializeOwned>(key: &str, default: T) -> Result<T> {
61 get(key).map(|opt| opt.unwrap_or(default))
62}
63
64#[inline]
66pub fn get_or_else<T: DeserializeOwned, F: FnOnce() -> T>(key: &str, f: F) -> Result<T> {
67 get(key).map(|opt| opt.unwrap_or_else(f))
68}
69
70#[cfg(target_arch = "wasm32")]
76pub fn set<T: Serialize>(key: &str, value: &T) -> Result<()> {
77 let value_json = serde_json::to_vec(value)?;
78
79 let result = unsafe {
80 super::ffi::state_set(
81 key.as_ptr() as i32,
82 key.len() as i32,
83 value_json.as_ptr() as i32,
84 value_json.len() as i32,
85 )
86 };
87
88 if result == 1 {
89 Ok(())
90 } else {
91 Err(Error::state(format!("Failed to set state key: {}", key)))
92 }
93}
94
95#[cfg(not(target_arch = "wasm32"))]
97pub fn set<T: Serialize>(_key: &str, _value: &T) -> Result<()> {
98 Ok(())
99}
100
101#[cfg(target_arch = "wasm32")]
107pub fn remove(key: &str) -> Result<()> {
108 let result = unsafe {
109 super::ffi::state_remove(key.as_ptr() as i32, key.len() as i32)
110 };
111
112 if result == 1 {
113 Ok(())
114 } else {
115 Err(Error::state(format!("Failed to remove state key: {}", key)))
116 }
117}
118
119#[cfg(not(target_arch = "wasm32"))]
121pub fn remove(_key: &str) -> Result<()> {
122 Ok(())
123}
124
125pub fn update<T, F>(key: &str, default: T, f: F) -> Result<T>
135where
136 T: DeserializeOwned + Serialize + Clone,
137 F: FnOnce(T) -> T,
138{
139 let current = get(key)?.unwrap_or(default);
140 let new_value = f(current);
141 set(key, &new_value)?;
142 Ok(new_value)
143}
144
145pub fn increment(key: &str) -> Result<i64> {
153 update(key, 0i64, |n| n + 1)
154}
155
156pub fn decrement(key: &str) -> Result<i64> {
158 update(key, 0i64, |n| n - 1)
159}
160
161pub fn push<T>(key: &str, value: &T) -> Result<()>
169where
170 T: Serialize + DeserializeOwned,
171{
172 let mut items: Vec<T> = get(key)?.unwrap_or_default();
173 let value_json = serde_json::to_value(value)?;
175 let typed_value: T = serde_json::from_value(value_json)?;
176 items.push(typed_value);
177 set(key, &items)
178}
179
180pub fn len(key: &str) -> Result<usize> {
182 let items: Vec<serde_json::Value> = get(key)?.unwrap_or_default();
183 Ok(items.len())
184}
185
186#[cfg(target_arch = "wasm32")]
188pub fn exists(key: &str) -> bool {
189 let ptr = unsafe {
190 super::ffi::state_get(key.as_ptr() as i32, key.len() as i32)
191 };
192 ptr != 0
193}
194
195#[cfg(not(target_arch = "wasm32"))]
197pub fn exists(_key: &str) -> bool {
198 false
199}
200
201pub struct ScopedState {
213 prefix: String,
214}
215
216impl ScopedState {
217 #[must_use]
219 pub fn new(prefix: impl Into<String>) -> Self {
220 let mut prefix = prefix.into();
221 if !prefix.ends_with(':') {
222 prefix.push(':');
223 }
224 Self { prefix }
225 }
226
227 fn key(&self, name: &str) -> String {
228 format!("{}{}", self.prefix, name)
229 }
230
231 pub fn get<T: DeserializeOwned>(&self, name: &str) -> Result<Option<T>> {
233 get(&self.key(name))
234 }
235
236 pub fn set<T: Serialize>(&self, name: &str, value: &T) -> Result<()> {
238 set(&self.key(name), value)
239 }
240
241 pub fn remove(&self, name: &str) -> Result<()> {
243 remove(&self.key(name))
244 }
245
246 pub fn exists(&self, name: &str) -> bool {
248 exists(&self.key(name))
249 }
250}
251
252#[inline]
254#[must_use]
255pub fn scoped(prefix: impl Into<String>) -> ScopedState {
256 ScopedState::new(prefix)
257}