use serde::de::DeserializeOwned;
use serde::Serialize;
use std::marker::PhantomData;
use crate::helpers::{nested_namespaces_with_key, not_found_object_info};
use crate::keys::Key;
use cosmwasm_std::{from_slice, to_vec, StdError, StdResult, Storage};
use std::ops::Deref;
#[derive(Debug, Clone)]
pub struct Path<T>
where
T: Serialize + DeserializeOwned,
{
pub(crate) storage_key: Vec<u8>,
data: PhantomData<T>,
}
impl<T> Deref for Path<T>
where
T: Serialize + DeserializeOwned,
{
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.storage_key
}
}
impl<T> Path<T>
where
T: Serialize + DeserializeOwned,
{
pub fn new(namespace: &[u8], keys: &[&[u8]]) -> Self {
let l = keys.len();
let storage_key = nested_namespaces_with_key(
&[namespace],
&keys[0..l - 1]
.iter()
.map(|k| Key::Ref(k))
.collect::<Vec<Key>>(),
keys[l - 1],
);
Path {
storage_key,
data: PhantomData,
}
}
pub fn save(&self, store: &mut dyn Storage, data: &T) -> StdResult<()> {
store.set(&self.storage_key, &to_vec(data)?);
Ok(())
}
pub fn remove(&self, store: &mut dyn Storage) {
store.remove(&self.storage_key);
}
pub fn load(&self, store: &dyn Storage) -> StdResult<T> {
if let Some(value) = store.get(&self.storage_key) {
from_slice(&value)
} else {
let object_info = not_found_object_info::<T>(&self.storage_key);
Err(StdError::not_found(object_info))
}
}
pub fn may_load(&self, store: &dyn Storage) -> StdResult<Option<T>> {
let value = store.get(&self.storage_key);
value.map(|v| from_slice(&v)).transpose()
}
pub fn has(&self, store: &dyn Storage) -> bool {
store.get(&self.storage_key).is_some()
}
pub fn update<A, E>(&self, store: &mut dyn Storage, action: A) -> Result<T, E>
where
A: FnOnce(Option<T>) -> Result<T, E>,
E: From<StdError>,
{
let input = self.may_load(store)?;
let output = action(input)?;
self.save(store, &output)?;
Ok(output)
}
}