use crate::{
storage::{self, unhashed, StorageAppend},
Never,
};
use codec::{Decode, Encode, EncodeLike, FullCodec};
pub trait StorageValue<T: FullCodec> {
type Query;
fn module_prefix() -> &'static [u8];
fn storage_prefix() -> &'static [u8];
fn from_optional_value_to_query(v: Option<T>) -> Self::Query;
fn from_query_to_optional_value(v: Self::Query) -> Option<T>;
fn storage_value_final_key() -> [u8; 32] {
crate::storage::storage_prefix(Self::module_prefix(), Self::storage_prefix())
}
}
impl<T: FullCodec, G: StorageValue<T>> storage::StorageValue<T> for G {
type Query = G::Query;
fn hashed_key() -> [u8; 32] {
Self::storage_value_final_key()
}
fn exists() -> bool {
unhashed::exists(&Self::storage_value_final_key())
}
fn get() -> Self::Query {
let value = unhashed::get(&Self::storage_value_final_key());
G::from_optional_value_to_query(value)
}
fn try_get() -> Result<T, ()> {
unhashed::get(&Self::storage_value_final_key()).ok_or(())
}
fn translate<O: Decode, F: FnOnce(Option<O>) -> Option<T>>(f: F) -> Result<Option<T>, ()> {
let key = Self::storage_value_final_key();
let maybe_old = unhashed::get_raw(&key)
.map(|old_data| O::decode(&mut &old_data[..]).map_err(|_| ()))
.transpose()?;
let maybe_new = f(maybe_old);
if let Some(new) = maybe_new.as_ref() {
new.using_encoded(|d| unhashed::put_raw(&key, d));
} else {
unhashed::kill(&key);
}
Ok(maybe_new)
}
fn put<Arg: EncodeLike<T>>(val: Arg) {
unhashed::put(&Self::storage_value_final_key(), &val)
}
fn set(maybe_val: Self::Query) {
if let Some(val) = G::from_query_to_optional_value(maybe_val) {
unhashed::put(&Self::storage_value_final_key(), &val)
} else {
unhashed::kill(&Self::storage_value_final_key())
}
}
fn kill() {
unhashed::kill(&Self::storage_value_final_key())
}
fn mutate<R, F: FnOnce(&mut G::Query) -> R>(f: F) -> R {
Self::try_mutate(|v| Ok::<R, Never>(f(v))).expect("`Never` can not be constructed; qed")
}
fn try_mutate<R, E, F: FnOnce(&mut G::Query) -> Result<R, E>>(f: F) -> Result<R, E> {
let mut val = G::get();
let ret = f(&mut val);
if ret.is_ok() {
match G::from_query_to_optional_value(val) {
Some(ref val) => G::put(val),
None => G::kill(),
}
}
ret
}
fn take() -> G::Query {
let key = Self::storage_value_final_key();
let value = unhashed::get(&key);
if value.is_some() {
unhashed::kill(&key)
}
G::from_optional_value_to_query(value)
}
fn append<Item, EncodeLikeItem>(item: EncodeLikeItem)
where
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
T: StorageAppend<Item>,
{
let key = Self::storage_value_final_key();
sp_io::storage::append(&key, item.encode());
}
}