use crate::browser::util::window;
use serde::{de::DeserializeOwned, Serialize};
use wasm_bindgen::JsValue;
use web_sys::Storage;
pub type Result<T> = std::result::Result<T, WebStorageError>;
#[allow(clippy::module_name_repetitions, clippy::pub_enum_variant_names)]
#[derive(Debug)]
pub enum WebStorageError {
GetStorageError(JsValue),
StorageNotFoundError,
ClearError(JsValue),
GetlengthError(JsValue),
GetKeyError(JsValue),
KeyNotFoundError,
RemoveError(JsValue),
GetError(JsValue),
InsertError(JsValue),
SerdeError(serde_json::Error),
}
pub struct LocalStorage;
impl WebStorage for LocalStorage {
fn storage() -> Result<Storage> {
window()
.local_storage()
.map_err(WebStorageError::GetStorageError)?
.ok_or(WebStorageError::StorageNotFoundError)
}
}
pub struct SessionStorage;
impl WebStorage for SessionStorage {
fn storage() -> Result<Storage> {
window()
.session_storage()
.map_err(WebStorageError::GetStorageError)?
.ok_or(WebStorageError::StorageNotFoundError)
}
}
pub trait WebStorage {
fn storage() -> Result<Storage>;
fn clear() -> Result<()> {
Self::storage()?
.clear()
.map_err(WebStorageError::ClearError)
}
fn len() -> Result<u32> {
Self::storage()?
.length()
.map_err(WebStorageError::GetlengthError)
}
fn key(index: u32) -> Result<String> {
Self::storage()?
.key(index)
.map_err(WebStorageError::GetKeyError)?
.ok_or(WebStorageError::KeyNotFoundError)
}
fn remove(key: impl AsRef<str>) -> Result<()> {
Self::storage()?
.remove_item(key.as_ref())
.map_err(WebStorageError::RemoveError)
}
fn get<T: DeserializeOwned>(key: impl AsRef<str>) -> Result<T> {
Self::storage()?
.get_item(key.as_ref())
.map_err(WebStorageError::GetError)?
.ok_or(WebStorageError::KeyNotFoundError)
.map(|value| serde_json::from_str(&value))?
.map_err(WebStorageError::SerdeError)
}
fn insert<T: Serialize + ?Sized>(key: impl AsRef<str>, value: &T) -> Result<()> {
let value = serde_json::to_string(value).map_err(WebStorageError::SerdeError)?;
Self::storage()?
.set_item(key.as_ref(), &value)
.map_err(WebStorageError::InsertError)
}
}
#[cfg(test)]
mod tests {
use wasm_bindgen_test::*;
use super::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn local_storage_insert_get() {
LocalStorage::clear().unwrap();
let value: String = {
LocalStorage::insert("a_key", "a_value").unwrap();
LocalStorage::get("a_key").unwrap()
};
assert_eq!("a_value", value)
}
#[wasm_bindgen_test]
fn local_storage_length_clear() {
LocalStorage::clear().unwrap();
assert_eq!(0, LocalStorage::len().unwrap());
LocalStorage::insert("key_1", "a_value").unwrap();
LocalStorage::insert("key_2", "a_value").unwrap();
assert_eq!(2, LocalStorage::len().unwrap());
LocalStorage::clear().unwrap();
assert_eq!(0, LocalStorage::len().unwrap());
}
#[wasm_bindgen_test]
fn local_storage_key() {
SessionStorage::clear().unwrap();
SessionStorage::insert("a_key", "a_value").unwrap();
assert_eq!("a_key", SessionStorage::key(0).unwrap());
}
#[wasm_bindgen_test]
fn local_storage_remove() {
SessionStorage::clear().unwrap();
SessionStorage::insert("a_key", "a_value").unwrap();
SessionStorage::remove("a_key").unwrap();
assert_eq!(0, SessionStorage::len().unwrap());
}
#[wasm_bindgen_test]
fn session_storage_insert_get() {
SessionStorage::clear().unwrap();
let value: String = {
SessionStorage::insert("a_key", "a_value").unwrap();
SessionStorage::get("a_key").unwrap()
};
assert_eq!("a_value", value)
}
#[wasm_bindgen_test]
fn session_storage_length_clear() {
SessionStorage::clear().unwrap();
assert_eq!(0, SessionStorage::len().unwrap());
SessionStorage::insert("key_1", "a_value").unwrap();
SessionStorage::insert("key_2", "a_value").unwrap();
assert_eq!(2, SessionStorage::len().unwrap());
SessionStorage::clear().unwrap();
assert_eq!(0, SessionStorage::len().unwrap());
}
#[wasm_bindgen_test]
fn session_storage_key() {
SessionStorage::clear().unwrap();
SessionStorage::insert("a_key", "a_value").unwrap();
assert_eq!("a_key", SessionStorage::key(0).unwrap());
}
#[wasm_bindgen_test]
fn session_storage_remove() {
SessionStorage::clear().unwrap();
SessionStorage::insert("a_key", "a_value").unwrap();
SessionStorage::remove("a_key").unwrap();
assert_eq!(0, SessionStorage::len().unwrap());
}
}