use codec::{FullCodec, Decode, EncodeLike, Encode};
use crate::{
storage::{
StorageAppend, StorageDecodeLength,
types::{OptionQuery, QueryKindTrait, OnEmptyGetter},
},
traits::{GetDefault, StorageInstance},
};
use fabric_metadata::{DefaultByteGetter, StorageEntryModifier};
use tetcore_std::prelude::*;
pub struct StorageMap<Prefix, Hasher, Key, Value, QueryKind=OptionQuery, OnEmpty=GetDefault>(
core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)>
);
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
crate::storage::generator::StorageMap<Key, Value>
for StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
where
Prefix: StorageInstance,
Hasher: crate::hash::StorageHasher,
Key: FullCodec,
Value: FullCodec,
QueryKind: QueryKindTrait<Value, OnEmpty>,
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
{
type Query = QueryKind::Query;
type Hasher = Hasher;
fn module_prefix() -> &'static [u8] {
Prefix::noble_prefix().as_bytes()
}
fn storage_prefix() -> &'static [u8] {
Prefix::STORAGE_PREFIX.as_bytes()
}
fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
QueryKind::from_optional_value_to_query(v)
}
fn from_query_to_optional_value(v: Self::Query) -> Option<Value> {
QueryKind::from_query_to_optional_value(v)
}
}
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty> crate::storage::StoragePrefixedMap<Value> for
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
where
Prefix: StorageInstance,
Hasher: crate::hash::StorageHasher,
Key: FullCodec,
Value: FullCodec,
QueryKind: QueryKindTrait<Value, OnEmpty>,
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
{
fn module_prefix() -> &'static [u8] {
<Self as crate::storage::generator::StorageMap<Key, Value>>::module_prefix()
}
fn storage_prefix() -> &'static [u8] {
<Self as crate::storage::generator::StorageMap<Key, Value>>::storage_prefix()
}
}
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
where
Prefix: StorageInstance,
Hasher: crate::hash::StorageHasher,
Key: FullCodec,
Value: FullCodec,
QueryKind: QueryKindTrait<Value, OnEmpty>,
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
{
pub fn hashed_key_for<KeyArg: EncodeLike<Key>>(key: KeyArg) -> Vec<u8> {
<Self as crate::storage::StorageMap<Key, Value>>::hashed_key_for(key)
}
pub fn contains_key<KeyArg: EncodeLike<Key>>(key: KeyArg) -> bool {
<Self as crate::storage::StorageMap<Key, Value>>::contains_key(key)
}
pub fn get<KeyArg: EncodeLike<Key>>(key: KeyArg) -> QueryKind::Query {
<Self as crate::storage::StorageMap<Key, Value>>::get(key)
}
pub fn try_get<KeyArg: EncodeLike<Key>>(key: KeyArg) -> Result<Value, ()> {
<Self as crate::storage::StorageMap<Key, Value>>::try_get(key)
}
pub fn swap<KeyArg1: EncodeLike<Key>, KeyArg2: EncodeLike<Key>>(key1: KeyArg1, key2: KeyArg2) {
<Self as crate::storage::StorageMap<Key, Value>>::swap(key1, key2)
}
pub fn insert<KeyArg: EncodeLike<Key>, ValArg: EncodeLike<Value>>(key: KeyArg, val: ValArg) {
<Self as crate::storage::StorageMap<Key, Value>>::insert(key, val)
}
pub fn remove<KeyArg: EncodeLike<Key>>(key: KeyArg) {
<Self as crate::storage::StorageMap<Key, Value>>::remove(key)
}
pub fn mutate<KeyArg: EncodeLike<Key>, R, F: FnOnce(&mut QueryKind::Query) -> R>(
key: KeyArg,
f: F
) -> R {
<Self as crate::storage::StorageMap<Key, Value>>::mutate(key, f)
}
pub fn try_mutate<KeyArg, R, E, F>(key: KeyArg, f: F) -> Result<R, E>
where
KeyArg: EncodeLike<Key>,
F: FnOnce(&mut QueryKind::Query) -> Result<R, E>,
{
<Self as crate::storage::StorageMap<Key, Value>>::try_mutate(key, f)
}
pub fn mutate_exists<KeyArg: EncodeLike<Key>, R, F: FnOnce(&mut Option<Value>) -> R>(
key: KeyArg,
f: F
) -> R {
<Self as crate::storage::StorageMap<Key, Value>>::mutate_exists(key, f)
}
pub fn try_mutate_exists<KeyArg, R, E, F>(key: KeyArg, f: F) -> Result<R, E>
where
KeyArg: EncodeLike<Key>,
F: FnOnce(&mut Option<Value>) -> Result<R, E>,
{
<Self as crate::storage::StorageMap<Key, Value>>::try_mutate_exists(key, f)
}
pub fn take<KeyArg: EncodeLike<Key>>(key: KeyArg) -> QueryKind::Query {
<Self as crate::storage::StorageMap<Key, Value>>::take(key)
}
pub fn append<Item, EncodeLikeItem, EncodeLikeKey>(key: EncodeLikeKey, item: EncodeLikeItem)
where
EncodeLikeKey: EncodeLike<Key>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
Value: StorageAppend<Item>
{
<Self as crate::storage::StorageMap<Key, Value>>::append(key, item)
}
pub fn decode_len<KeyArg: EncodeLike<Key>>(key: KeyArg) -> Option<usize>
where Value: StorageDecodeLength,
{
<Self as crate::storage::StorageMap<Key, Value>>::decode_len(key)
}
pub fn migrate_key<OldHasher: crate::hash::StorageHasher, KeyArg: EncodeLike<Key>>(
key: KeyArg
) -> Option<Value> {
<Self as crate::storage::StorageMap<Key, Value>>::migrate_key::<OldHasher, _>(key)
}
pub fn remove_all() {
<Self as crate::storage::StoragePrefixedMap<Value>>::remove_all()
}
pub fn iter_values() -> crate::storage::PrefixIterator<Value> {
<Self as crate::storage::StoragePrefixedMap<Value>>::iter_values()
}
pub fn translate_values<OldValue: Decode, F: Fn(OldValue) -> Option<Value>>(f: F) {
<Self as crate::storage::StoragePrefixedMap<Value>>::translate_values(f)
}
}
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
where
Prefix: StorageInstance,
Hasher: crate::hash::StorageHasher + crate::ReversibleStorageHasher,
Key: FullCodec,
Value: FullCodec,
QueryKind: QueryKindTrait<Value, OnEmpty>,
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
{
pub fn iter() -> crate::storage::PrefixIterator<(Key, Value)> {
<Self as crate::storage::IterableStorageMap<Key, Value>>::iter()
}
pub fn drain() -> crate::storage::PrefixIterator<(Key, Value)> {
<Self as crate::storage::IterableStorageMap<Key, Value>>::drain()
}
pub fn translate<O: Decode, F: Fn(Key, O) -> Option<Value>>(f: F) {
<Self as crate::storage::IterableStorageMap<Key, Value>>::translate(f)
}
}
pub trait StorageMapMetadata {
const MODIFIER: StorageEntryModifier;
const NAME: &'static str;
const DEFAULT: DefaultByteGetter;
const HASHER: fabric_metadata::StorageHasher;
}
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty> StorageMapMetadata
for StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty> where
Prefix: StorageInstance,
Hasher: crate::hash::StorageHasher,
Key: FullCodec,
Value: FullCodec,
QueryKind: QueryKindTrait<Value, OnEmpty>,
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
{
const MODIFIER: StorageEntryModifier = QueryKind::METADATA;
const HASHER: fabric_metadata::StorageHasher = Hasher::METADATA;
const NAME: &'static str = Prefix::STORAGE_PREFIX;
const DEFAULT: DefaultByteGetter =
DefaultByteGetter(&OnEmptyGetter::<QueryKind::Query, OnEmpty>(core::marker::PhantomData));
}
#[cfg(test)]
mod test {
use super::*;
use tet_io::{TestExternalities, hashing::twox_128};
use crate::hash::*;
use crate::storage::types::ValueQuery;
use fabric_metadata::StorageEntryModifier;
struct Prefix;
impl StorageInstance for Prefix {
fn noble_prefix() -> &'static str { "test" }
const STORAGE_PREFIX: &'static str = "foo";
}
struct ADefault;
impl crate::traits::Get<u32> for ADefault {
fn get() -> u32 {
97
}
}
#[test]
fn test() {
type A = StorageMap<Prefix, Blake2_128Concat, u16, u32, OptionQuery>;
type AValueQueryWithAnOnEmpty = StorageMap<
Prefix, Blake2_128Concat, u16, u32, ValueQuery, ADefault
>;
type B = StorageMap<Prefix, Blake2_256, u16, u32, ValueQuery>;
type C = StorageMap<Prefix, Blake2_128Concat, u16, u8, ValueQuery>;
type WithLen = StorageMap<Prefix, Blake2_128Concat, u16, Vec<u32>>;
TestExternalities::default().execute_with(|| {
let mut k: Vec<u8> = vec![];
k.extend(&twox_128(b"test"));
k.extend(&twox_128(b"foo"));
k.extend(&3u16.blake2_128_concat());
assert_eq!(A::hashed_key_for(3).to_vec(), k);
assert_eq!(A::contains_key(3), false);
assert_eq!(A::get(3), None);
assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97);
A::insert(3, 10);
assert_eq!(A::contains_key(3), true);
assert_eq!(A::get(3), Some(10));
assert_eq!(A::try_get(3), Ok(10));
assert_eq!(AValueQueryWithAnOnEmpty::get(3), 10);
A::swap(3, 2);
assert_eq!(A::contains_key(3), false);
assert_eq!(A::contains_key(2), true);
assert_eq!(A::get(3), None);
assert_eq!(A::try_get(3), Err(()));
assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97);
assert_eq!(A::get(2), Some(10));
assert_eq!(AValueQueryWithAnOnEmpty::get(2), 10);
A::remove(2);
assert_eq!(A::contains_key(2), false);
assert_eq!(A::get(2), None);
AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2);
AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2);
assert_eq!(AValueQueryWithAnOnEmpty::contains_key(2), true);
assert_eq!(AValueQueryWithAnOnEmpty::get(2), 97 * 4);
A::remove(2);
let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| {
*v = *v * 2; Ok(())
});
let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| {
*v = *v * 2; Ok(())
});
assert_eq!(A::contains_key(2), true);
assert_eq!(A::get(2), Some(97 * 4));
A::remove(2);
let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| {
*v = *v * 2; Err(())
});
assert_eq!(A::contains_key(2), false);
A::remove(2);
AValueQueryWithAnOnEmpty::mutate_exists(2, |v| {
assert!(v.is_none());
*v = Some(10);
});
assert_eq!(A::contains_key(2), true);
assert_eq!(A::get(2), Some(10));
AValueQueryWithAnOnEmpty::mutate_exists(2, |v| {
*v = Some(v.unwrap() * 10);
});
assert_eq!(A::contains_key(2), true);
assert_eq!(A::get(2), Some(100));
A::remove(2);
let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| {
assert!(v.is_none());
*v = Some(10);
Ok(())
});
assert_eq!(A::contains_key(2), true);
assert_eq!(A::get(2), Some(10));
let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| {
*v = Some(v.unwrap() * 10);
Ok(())
});
assert_eq!(A::contains_key(2), true);
assert_eq!(A::get(2), Some(100));
let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| {
*v = Some(v.unwrap() * 10);
Err(())
});
assert_eq!(A::contains_key(2), true);
assert_eq!(A::get(2), Some(100));
A::insert(2, 10);
assert_eq!(A::take(2), Some(10));
assert_eq!(A::contains_key(2), false);
assert_eq!(AValueQueryWithAnOnEmpty::take(2), 97);
assert_eq!(A::contains_key(2), false);
B::insert(2, 10);
assert_eq!(A::migrate_key::<Blake2_256, _>(2), Some(10));
assert_eq!(A::contains_key(2), true);
assert_eq!(A::get(2), Some(10));
A::insert(3, 10);
A::insert(4, 10);
A::remove_all();
assert_eq!(A::contains_key(3), false);
assert_eq!(A::contains_key(4), false);
A::insert(3, 10);
A::insert(4, 10);
assert_eq!(A::iter_values().collect::<Vec<_>>(), vec![10, 10]);
C::insert(3, 10);
C::insert(4, 10);
A::translate_values::<u8,_>(|v| Some((v * 2).into()));
assert_eq!(A::iter().collect::<Vec<_>>(), vec![(4, 20), (3, 20)]);
A::insert(3, 10);
A::insert(4, 10);
assert_eq!(A::iter().collect::<Vec<_>>(), vec![(4, 10), (3, 10)]);
assert_eq!(A::drain().collect::<Vec<_>>(), vec![(4, 10), (3, 10)]);
assert_eq!(A::iter().collect::<Vec<_>>(), vec![]);
C::insert(3, 10);
C::insert(4, 10);
A::translate::<u8,_>(|k, v| Some((k * v as u16).into()));
assert_eq!(A::iter().collect::<Vec<_>>(), vec![(4, 40), (3, 30)]);
assert_eq!(A::MODIFIER, StorageEntryModifier::Optional);
assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default);
assert_eq!(A::HASHER, fabric_metadata::StorageHasher::Blake2_128Concat);
assert_eq!(
AValueQueryWithAnOnEmpty::HASHER,
fabric_metadata::StorageHasher::Blake2_128Concat
);
assert_eq!(A::NAME, "foo");
assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 97u32.encode());
assert_eq!(A::DEFAULT.0.default_byte(), Option::<u32>::None.encode());
WithLen::remove_all();
assert_eq!(WithLen::decode_len(3), None);
WithLen::append(0, 10);
assert_eq!(WithLen::decode_len(0), Some(1));
})
}
}