#[allow(unused_imports)]
use super::error::{Error, Result};
use serde::{de::DeserializeOwned, Serialize};
#[cfg(target_arch = "wasm32")]
pub fn get<T: DeserializeOwned>(key: &str) -> Result<Option<T>> {
let ptr = unsafe {
super::ffi::state_get(key.as_ptr() as i32, key.len() as i32)
};
if ptr == 0 {
return Ok(None);
}
let bytes = unsafe { super::ffi::read_length_prefixed(ptr) };
let value: T = serde_json::from_slice(&bytes)?;
Ok(Some(value))
}
#[cfg(not(target_arch = "wasm32"))]
pub fn get<T: DeserializeOwned>(_key: &str) -> Result<Option<T>> {
Ok(None)
}
#[inline]
pub fn get_or<T: DeserializeOwned>(key: &str, default: T) -> Result<T> {
get(key).map(|opt| opt.unwrap_or(default))
}
#[inline]
pub fn get_or_else<T: DeserializeOwned, F: FnOnce() -> T>(key: &str, f: F) -> Result<T> {
get(key).map(|opt| opt.unwrap_or_else(f))
}
#[cfg(target_arch = "wasm32")]
pub fn set<T: Serialize>(key: &str, value: &T) -> Result<()> {
let value_json = serde_json::to_vec(value)?;
let result = unsafe {
super::ffi::state_set(
key.as_ptr() as i32,
key.len() as i32,
value_json.as_ptr() as i32,
value_json.len() as i32,
)
};
if result == 1 {
Ok(())
} else {
Err(Error::state(format!("Failed to set state key: {}", key)))
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn set<T: Serialize>(_key: &str, _value: &T) -> Result<()> {
Ok(())
}
#[cfg(target_arch = "wasm32")]
pub fn remove(key: &str) -> Result<()> {
let result = unsafe {
super::ffi::state_remove(key.as_ptr() as i32, key.len() as i32)
};
if result == 1 {
Ok(())
} else {
Err(Error::state(format!("Failed to remove state key: {}", key)))
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn remove(_key: &str) -> Result<()> {
Ok(())
}
pub fn update<T, F>(key: &str, default: T, f: F) -> Result<T>
where
T: DeserializeOwned + Serialize + Clone,
F: FnOnce(T) -> T,
{
let current = get(key)?.unwrap_or(default);
let new_value = f(current);
set(key, &new_value)?;
Ok(new_value)
}
pub fn increment(key: &str) -> Result<i64> {
update(key, 0i64, |n| n + 1)
}
pub fn decrement(key: &str) -> Result<i64> {
update(key, 0i64, |n| n - 1)
}
pub fn push<T>(key: &str, value: &T) -> Result<()>
where
T: Serialize + DeserializeOwned,
{
let mut items: Vec<T> = get(key)?.unwrap_or_default();
let value_json = serde_json::to_value(value)?;
let typed_value: T = serde_json::from_value(value_json)?;
items.push(typed_value);
set(key, &items)
}
pub fn len(key: &str) -> Result<usize> {
let items: Vec<serde_json::Value> = get(key)?.unwrap_or_default();
Ok(items.len())
}
#[cfg(target_arch = "wasm32")]
pub fn exists(key: &str) -> bool {
let ptr = unsafe {
super::ffi::state_get(key.as_ptr() as i32, key.len() as i32)
};
ptr != 0
}
#[cfg(not(target_arch = "wasm32"))]
pub fn exists(_key: &str) -> bool {
false
}
pub struct ScopedState {
prefix: String,
}
impl ScopedState {
#[must_use]
pub fn new(prefix: impl Into<String>) -> Self {
let mut prefix = prefix.into();
if !prefix.ends_with(':') {
prefix.push(':');
}
Self { prefix }
}
fn key(&self, name: &str) -> String {
format!("{}{}", self.prefix, name)
}
pub fn get<T: DeserializeOwned>(&self, name: &str) -> Result<Option<T>> {
get(&self.key(name))
}
pub fn set<T: Serialize>(&self, name: &str, value: &T) -> Result<()> {
set(&self.key(name), value)
}
pub fn remove(&self, name: &str) -> Result<()> {
remove(&self.key(name))
}
pub fn exists(&self, name: &str) -> bool {
exists(&self.key(name))
}
}
#[inline]
#[must_use]
pub fn scoped(prefix: impl Into<String>) -> ScopedState {
ScopedState::new(prefix)
}