use hashbrown::HashMap;
use scale_info::{PortableRegistry, TypeDef};
use crate::{
utils::{
retain,
validation::{get_type_def_variant_hash, get_type_hash},
},
Metadata,
};
use super::{concat_and_hash3, Hash, HASH_LEN};
pub struct OuterEnumHashes {
call_hash: (u32, Hash),
error_hash: (u32, Hash),
event_hash: (u32, Hash),
}
impl OuterEnumHashes {
pub fn new(
metadata: &Metadata,
specific_pallets: Option<&[&str]>,
specific_runtimes: Option<&[&str]>,
) -> Self {
let filter = |names: Option<&[&str]>, name: &str| match names {
Some(names) => names.contains(&name),
None => true,
};
let mut check_enum_type_id = retain::keep_outer_enum(
metadata,
&mut |name| filter(specific_pallets, name),
&mut |name| filter(specific_runtimes, name),
);
let variants = |filter: bool| {
if !filter {
specific_pallets
} else {
None
}
};
fn get_enum_hash(
registry: &PortableRegistry,
id: u32,
only_these_variants: Option<&[&str]>,
) -> Hash {
let ty = registry
.types
.get(id as usize)
.expect("Metadata should contain enum type in registry");
if let TypeDef::Variant(variant) = &ty.ty.type_def {
get_type_def_variant_hash(
registry,
variant,
only_these_variants,
&mut HashMap::new(),
&OuterEnumHashes::empty(),
)
} else {
get_type_hash(registry, id, &OuterEnumHashes::empty())
}
}
let enums = &metadata.outer_enums;
let call_variants = variants(check_enum_type_id(enums.call_enum_ty));
let call_hash = get_enum_hash(metadata.types(), enums.call_enum_ty, call_variants);
let event_variants = variants(check_enum_type_id(enums.event_enum_ty));
let event_hash = get_enum_hash(metadata.types(), enums.event_enum_ty, event_variants);
let error_variants = variants(check_enum_type_id(enums.error_enum_ty));
let error_hash = get_enum_hash(metadata.types(), enums.error_enum_ty, error_variants);
Self {
call_hash: (enums.call_enum_ty, call_hash),
error_hash: (enums.error_enum_ty, error_hash),
event_hash: (enums.event_enum_ty, event_hash),
}
}
pub fn empty() -> Self {
Self {
call_hash: (u32::MAX, [0; HASH_LEN]),
error_hash: (u32::MAX, [0; HASH_LEN]),
event_hash: (u32::MAX, [0; HASH_LEN]),
}
}
pub fn combined_hash(&self) -> Hash {
concat_and_hash3(&self.call_hash.1, &self.error_hash.1, &self.event_hash.1)
}
pub fn resolve(&self, id: u32) -> Option<[u8; HASH_LEN]> {
match id {
e if e == self.error_hash.0 => Some(self.error_hash.1),
e if e == self.event_hash.0 => Some(self.event_hash.1),
e if e == self.call_hash.0 => Some(self.call_hash.1),
_ => None,
}
}
}