use crate::methods::constant_type_info::{ConstantInfo, ConstantInfoError, ConstantTypeInfo};
use crate::utils::{DecodeErrorTrace, decode_with_error_tracing};
use alloc::vec::Vec;
use scale_type_resolver::TypeResolver;
#[non_exhaustive]
#[allow(missing_docs)]
#[derive(Clone, Debug, thiserror::Error)]
pub enum ConstantDecodeError<TypeId> {
#[error("Cannot get constant info: {0}")]
CannotGetInfo(ConstantInfoError<'static>),
#[error("Cannot decode constant: {reason}")]
CannotDecodeValue {
ty: TypeId,
reason: DecodeErrorTrace,
},
#[error("There were leftover bytes attempting to decode the constant")]
LeftoverBytes { bytes: Vec<u8> },
}
pub fn decode_constant<'info, 'resolver, Info, Resolver, V>(
pallet_name: &str,
constant_name: &str,
info: &'info Info,
type_resolver: &'resolver V::TypeResolver,
visitor: V,
) -> Result<V::Value<'info, 'resolver>, ConstantDecodeError<Info::TypeId>>
where
Info: ConstantTypeInfo,
Info::TypeId: Clone + core::fmt::Debug,
Resolver: TypeResolver<TypeId = Info::TypeId>,
V: scale_decode::Visitor<TypeResolver = Resolver>,
V::Error: core::fmt::Debug,
{
let info = info
.constant_info(pallet_name, constant_name)
.map_err(|e| ConstantDecodeError::CannotGetInfo(e.into_owned()))?;
decode_constant_with_info(&info, type_resolver, visitor)
}
pub fn decode_constant_with_info<'info, 'resolver, V>(
info: &ConstantInfo<'info, <V::TypeResolver as TypeResolver>::TypeId>,
type_resolver: &'resolver V::TypeResolver,
visitor: V,
) -> Result<
V::Value<'info, 'resolver>,
ConstantDecodeError<<V::TypeResolver as TypeResolver>::TypeId>,
>
where
V: scale_decode::Visitor,
V::Error: core::fmt::Debug,
{
let type_id = info.type_id.clone();
let cursor = &mut &*info.bytes;
let value = decode_with_error_tracing(cursor, type_id.clone(), type_resolver, visitor)
.map_err(|e| ConstantDecodeError::CannotDecodeValue {
ty: type_id,
reason: e,
})?;
if !cursor.is_empty() {
Err(ConstantDecodeError::LeftoverBytes {
bytes: cursor.to_vec(),
})
} else {
Ok(value)
}
}