use scale_info::{form::PortableForm, Field, Path, Type};
use crate::std::vec::Vec;
use crate::cards::Info;
use crate::error::RegistryInternalError;
use crate::special_indicators::{Hint, SpecialtyH256, SpecialtyUnsignedInteger};
use crate::traits::SignedExtensionMetadata;
#[derive(Clone, Copy, Debug)]
pub struct SpecialtySet {
pub compact_at: Option<u32>,
pub hint: Hint,
}
impl SpecialtySet {
pub fn new() -> Self {
Self {
compact_at: None,
hint: Hint::None,
}
}
pub fn reject_compact(&self) -> Result<(), RegistryInternalError> {
if let Some(id) = self.compact_at {
Err(RegistryInternalError::UnexpectedCompactInsides { id })
} else {
Ok(())
}
}
pub fn update_from_path(&mut self, path: &Path<PortableForm>) {
if let Hint::None = self.hint {
self.hint = Hint::from_path(path);
}
}
pub fn forget_hint(&mut self) {
if let Hint::ChargeAssetTxPayment = self.hint {
} else {
self.hint = Hint::None;
}
}
pub fn unsigned_integer(&self) -> SpecialtyUnsignedInteger {
self.hint.unsigned_integer()
}
pub fn hash256(&self) -> SpecialtyH256 {
self.hint.hash256()
}
}
impl Default for SpecialtySet {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct Checker {
pub specialty_set: SpecialtySet,
pub cycle_check: Vec<u32>,
}
impl Checker {
pub fn new() -> Self {
Self {
specialty_set: SpecialtySet::new(),
cycle_check: Vec::new(),
}
}
pub fn reject_compact(&self) -> Result<(), RegistryInternalError> {
self.specialty_set.reject_compact()
}
pub fn forget_hint(&mut self) {
self.specialty_set.forget_hint()
}
pub fn update_for_field(
&self,
field: &Field<PortableForm>,
) -> Result<Self, RegistryInternalError> {
let mut checker = self.clone();
if let Hint::None = checker.specialty_set.hint {
checker.specialty_set.hint = Hint::from_field(field);
}
checker.check_id(field.ty.id)?;
Ok(checker)
}
pub fn update_for_ty(
&self,
ty: &Type<PortableForm>,
id: u32,
) -> Result<Self, RegistryInternalError> {
let mut checker = self.clone();
checker.check_id(id)?;
checker.specialty_set.update_from_path(&ty.path);
Ok(checker)
}
pub fn drop_cycle_check(&mut self) {
self.cycle_check.clear()
}
pub fn check_id(&mut self, id: u32) -> Result<(), RegistryInternalError> {
if self.cycle_check.contains(&id) {
Err(RegistryInternalError::CyclicMetadata { id })
} else {
self.cycle_check.push(id);
Ok(())
}
}
}
impl Default for Checker {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct Propagated {
pub checker: Checker,
pub info: Vec<Info>,
}
impl Propagated {
pub fn new() -> Self {
Self {
checker: Checker::new(),
info: Vec::new(),
}
}
pub fn from_ext_meta(signed_ext_meta: &SignedExtensionMetadata) -> Self {
Self {
checker: Checker {
specialty_set: SpecialtySet {
compact_at: None,
hint: Hint::from_ext_meta(signed_ext_meta),
},
cycle_check: Vec::new(),
},
info: Vec::new(),
}
}
pub fn with_checker(checker: Checker) -> Self {
Self {
checker,
info: Vec::new(),
}
}
pub fn for_field(
checker: &Checker,
field: &Field<PortableForm>,
) -> Result<Self, RegistryInternalError> {
Ok(Self {
checker: Checker::update_for_field(checker, field)?,
info: Vec::new(),
})
}
pub fn for_ty(
checker: &Checker,
ty: &Type<PortableForm>,
id: u32,
) -> Result<Self, RegistryInternalError> {
Ok(Self {
checker: Checker::update_for_ty(checker, ty, id)?,
info: Vec::new(),
})
}
pub fn compact_at(&self) -> Option<u32> {
self.checker.specialty_set.compact_at
}
pub fn reject_compact(&self) -> Result<(), RegistryInternalError> {
self.checker.specialty_set.reject_compact()
}
pub fn forget_hint(&mut self) {
self.checker.forget_hint()
}
pub fn add_info(&mut self, info_update: &Info) {
if !info_update.is_empty() {
self.info.push(info_update.clone())
}
}
pub fn add_info_slice(&mut self, info_update_slice: &[Info]) {
self.info.extend_from_slice(info_update_slice)
}
}
impl Default for Propagated {
fn default() -> Self {
Self::new()
}
}