use crate::hash::{ReversibleStorageHasher, StorageHasher};
use alloc::{boxed::Box, vec::Vec};
use codec::{Encode, EncodeLike, FullCodec, MaxEncodedLen};
use paste::paste;
use scale_info::StaticTypeInfo;
pub struct Key<Hasher, KeyType>(core::marker::PhantomData<(Hasher, KeyType)>);
pub trait KeyGenerator {
type Key: EncodeLike<Self::Key> + StaticTypeInfo;
type KArg: Encode + EncodeLike<Self::KArg>;
type HashFn: FnOnce(&[u8]) -> Vec<u8>;
type HArg;
const HASHER_METADATA: &'static [sp_metadata_ir::StorageHasherIR];
fn final_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8>;
fn migrate_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(
key: &KArg,
hash_fns: Self::HArg,
) -> Vec<u8>;
}
pub trait KeyGeneratorMaxEncodedLen: KeyGenerator {
fn key_max_encoded_len() -> usize;
}
pub trait KeyGeneratorInner: KeyGenerator {
type Hasher: StorageHasher;
fn final_hash(encoded: &[u8]) -> Vec<u8>;
}
impl<H: StorageHasher, K: FullCodec + StaticTypeInfo> KeyGenerator for Key<H, K> {
type Key = K;
type KArg = (K,);
type HashFn = Box<dyn FnOnce(&[u8]) -> Vec<u8>>;
type HArg = (Self::HashFn,);
const HASHER_METADATA: &'static [sp_metadata_ir::StorageHasherIR] = &[H::METADATA];
fn final_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8> {
H::hash(&key.to_encoded_iter().next().expect("should have at least one element!"))
.as_ref()
.to_vec()
}
fn migrate_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(
key: &KArg,
hash_fns: Self::HArg,
) -> Vec<u8> {
(hash_fns.0)(&key.to_encoded_iter().next().expect("should have at least one element!"))
}
}
impl<H: StorageHasher, K: FullCodec + MaxEncodedLen + StaticTypeInfo> KeyGeneratorMaxEncodedLen
for Key<H, K>
{
fn key_max_encoded_len() -> usize {
H::max_len::<K>()
}
}
impl<H: StorageHasher, K: FullCodec + StaticTypeInfo> KeyGeneratorInner for Key<H, K> {
type Hasher = H;
fn final_hash(encoded: &[u8]) -> Vec<u8> {
H::hash(encoded).as_ref().to_vec()
}
}
#[impl_trait_for_tuples::impl_for_tuples(1, 18)]
#[tuple_types_custom_trait_bound(KeyGeneratorInner)]
impl KeyGenerator for Tuple {
for_tuples!( type Key = ( #(Tuple::Key),* ); );
for_tuples!( type KArg = ( #(Tuple::Key),* ); );
for_tuples!( type HArg = ( #(Tuple::HashFn),* ); );
type HashFn = Box<dyn FnOnce(&[u8]) -> Vec<u8>>;
const HASHER_METADATA: &'static [sp_metadata_ir::StorageHasherIR] =
&[for_tuples!( #(Tuple::Hasher::METADATA),* )];
fn final_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8> {
let mut final_key = Vec::new();
let mut iter = key.to_encoded_iter();
for_tuples!(
#(
let next_encoded = iter.next().expect("KArg number should be equal to Key number");
final_key.extend_from_slice(&Tuple::final_hash(&next_encoded));
)*
);
final_key
}
fn migrate_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(
key: &KArg,
hash_fns: Self::HArg,
) -> Vec<u8> {
let mut migrated_key = Vec::new();
let mut iter = key.to_encoded_iter();
for_tuples!(
#(
let next_encoded = iter.next().expect("KArg number should be equal to Key number");
migrated_key.extend_from_slice(&(hash_fns.Tuple)(&next_encoded));
)*
);
migrated_key
}
}
#[impl_trait_for_tuples::impl_for_tuples(1, 18)]
#[tuple_types_custom_trait_bound(KeyGeneratorInner + KeyGeneratorMaxEncodedLen)]
impl KeyGeneratorMaxEncodedLen for Tuple {
fn key_max_encoded_len() -> usize {
let mut len = 0usize;
for_tuples!(
#(
len = len.saturating_add(Tuple::key_max_encoded_len());
)*
);
len
}
}
pub trait EncodeLikeTuple<T>: crate::storage::private::Sealed {}
macro_rules! impl_encode_like_tuples {
($($elem:ident),+) => {
paste! {
impl<$($elem: Encode,)+ $([<$elem $elem>]: Encode + EncodeLike<$elem>,)+>
EncodeLikeTuple<($($elem,)+)> for
($([<$elem $elem>],)+) {}
impl<$($elem: Encode,)+ $([<$elem $elem>]: Encode + EncodeLike<$elem>,)+>
EncodeLikeTuple<($($elem,)+)> for
&($([<$elem $elem>],)+) {}
}
};
}
impl_encode_like_tuples!(A);
impl_encode_like_tuples!(A, B);
impl_encode_like_tuples!(A, B, C);
impl_encode_like_tuples!(A, B, C, D);
impl_encode_like_tuples!(A, B, C, D, E);
impl_encode_like_tuples!(A, B, C, D, E, F);
impl_encode_like_tuples!(A, B, C, D, E, F, G);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q, R);
impl<'a, T: EncodeLike<U> + EncodeLikeTuple<U>, U: Encode> EncodeLikeTuple<U>
for codec::Ref<'a, T, U>
{
}
pub trait TupleToEncodedIter {
fn to_encoded_iter(&self) -> alloc::vec::IntoIter<Vec<u8>>;
}
#[impl_trait_for_tuples::impl_for_tuples(1, 18)]
#[tuple_types_custom_trait_bound(Encode)]
impl TupleToEncodedIter for Tuple {
fn to_encoded_iter(&self) -> alloc::vec::IntoIter<Vec<u8>> {
[for_tuples!( #(self.Tuple.encode()),* )].to_vec().into_iter()
}
}
impl<T: TupleToEncodedIter> TupleToEncodedIter for &T {
fn to_encoded_iter(&self) -> alloc::vec::IntoIter<Vec<u8>> {
(*self).to_encoded_iter()
}
}
impl<'a, T: EncodeLike<U> + TupleToEncodedIter, U: Encode> TupleToEncodedIter
for codec::Ref<'a, T, U>
{
fn to_encoded_iter(&self) -> alloc::vec::IntoIter<Vec<u8>> {
use core::ops::Deref as _;
self.deref().to_encoded_iter()
}
}
pub trait ReversibleKeyGenerator: KeyGenerator {
type ReversibleHasher;
fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error>;
}
impl<H: ReversibleStorageHasher, K: FullCodec + StaticTypeInfo> ReversibleKeyGenerator
for Key<H, K>
{
type ReversibleHasher = H;
fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> {
let mut current_key_material = Self::ReversibleHasher::reverse(key_material);
let key = K::decode(&mut current_key_material)?;
Ok((key, current_key_material))
}
}
#[impl_trait_for_tuples::impl_for_tuples(2, 18)]
#[tuple_types_custom_trait_bound(ReversibleKeyGenerator + KeyGeneratorInner)]
impl ReversibleKeyGenerator for Tuple {
for_tuples!( type ReversibleHasher = ( #(Tuple::ReversibleHasher),* ); );
fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> {
let mut current_key_material = key_material;
Ok((
(for_tuples! {
#({
let (key, material) = Tuple::decode_final_key(current_key_material)?;
current_key_material = material;
key
}),*
}),
current_key_material,
))
}
}
pub trait HasKeyPrefix<P>: KeyGenerator {
type Suffix;
fn partial_key(prefix: P) -> Vec<u8>;
}
pub trait HasReversibleKeyPrefix<P>: ReversibleKeyGenerator + HasKeyPrefix<P> {
fn decode_partial_key(key_material: &[u8]) -> Result<Self::Suffix, codec::Error>;
}
frame_support_procedural::impl_key_prefix_for_tuples!();