use cosmwasm_std::storage_keys::namespace_with_key;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::marker::PhantomData;
use crate::helpers::not_found_object_info;
use cosmwasm_std::{from_json, to_json_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 calculated_len = 1 + keys.len() - 1;
let mut combined: Vec<&[u8]> = Vec::with_capacity(calculated_len);
combined.push(namespace);
combined.extend(keys[0..l - 1].iter());
debug_assert_eq!(calculated_len, combined.len()); let storage_key = namespace_with_key(&combined, 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_json_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_json(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_json(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)
}
}