use alloc::string::String;
#[cfg(feature = "scale-info")]
use alloc::string::ToString;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Format {
pub store: StoreFormat,
pub order: OrderFormat,
}
impl Format {
pub fn new(store: StoreFormat, order: OrderFormat) -> Self {
Format { store, order }
}
#[cfg(feature = "scale-info")]
pub fn from_metadata(
ty: &scale_info::TypeDefBitSequence<scale_info::form::PortableForm>,
types: &scale_info::PortableRegistry,
) -> Result<Format, FromMetadataError> {
let bit_store_ty = ty.bit_store_type.id;
let bit_order_ty = ty.bit_order_type.id;
let bit_store_def = &types
.resolve(bit_store_ty)
.ok_or(FromMetadataError::StoreFormatNotFound(bit_store_ty))?
.type_def;
let bit_order_def = types
.resolve(bit_order_ty)
.ok_or(FromMetadataError::OrderFormatNotFound(bit_order_ty))?
.path
.ident()
.ok_or(FromMetadataError::NoBitOrderIdent)?;
use scale_info::{TypeDef, TypeDefPrimitive};
let bit_store_out = match bit_store_def {
TypeDef::Primitive(TypeDefPrimitive::U8) => Some(StoreFormat::U8),
TypeDef::Primitive(TypeDefPrimitive::U16) => Some(StoreFormat::U16),
TypeDef::Primitive(TypeDefPrimitive::U32) => Some(StoreFormat::U32),
TypeDef::Primitive(TypeDefPrimitive::U64) => Some(StoreFormat::U64),
_ => None,
}
.ok_or_else(|| {
FromMetadataError::StoreFormatNotSupported(alloc::format!("{bit_store_def:?}"))
})?;
let bit_order_out = match &*bit_order_def {
"Lsb0" => Some(OrderFormat::Lsb0),
"Msb0" => Some(OrderFormat::Msb0),
_ => None,
}
.ok_or(FromMetadataError::OrderFormatNotSupported(bit_order_def.to_string()))?;
Ok(Format { store: bit_store_out, order: bit_order_out })
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum OrderFormat {
Lsb0,
Msb0,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum StoreFormat {
U8,
U16,
U32,
U64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FromMetadataError {
OrderFormatNotFound(u32),
StoreFormatNotFound(u32),
NoBitOrderIdent,
StoreFormatNotSupported(String),
OrderFormatNotSupported(String),
}
impl core::fmt::Display for FromMetadataError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
FromMetadataError::OrderFormatNotFound(n) => {
write!(f, "Bit order type {n} not found in registry")
}
FromMetadataError::StoreFormatNotFound(n) => {
write!(f, "Bit store type {n} not found in registry")
}
FromMetadataError::NoBitOrderIdent => {
write!(f, "Bit order cannot be identified")
}
FromMetadataError::StoreFormatNotSupported(s) => {
write!(f, "Bit store type '{s}' is not supported")
}
FromMetadataError::OrderFormatNotSupported(s) => {
write!(f, "Bit order type '{s}' is not supported")
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for FromMetadataError {}
#[cfg(feature = "scale-info")]
#[cfg(test)]
mod test {
use super::*;
fn make_type<T: scale_info::TypeInfo + 'static>() -> (u32, scale_info::PortableRegistry) {
let m = scale_info::MetaType::new::<T>();
let mut types = scale_info::Registry::new();
let id = types.register_type(&m);
let portable_registry: scale_info::PortableRegistry = types.into();
(id.id, portable_registry)
}
fn assert_format<T: scale_info::TypeInfo + 'static>(store: StoreFormat, order: OrderFormat) {
let (id, types) = make_type::<T>();
let ty = match &types.resolve(id).unwrap().type_def {
scale_info::TypeDef::BitSequence(b) => b,
_ => panic!("expected type to look like a bit sequence"),
};
let actual_format =
crate::Format::from_metadata(ty, &types).expect("can obtain BitSeq Format from type");
assert_eq!(Format::new(store, order), actual_format);
}
#[test]
fn format_extracted_properly() {
use bitvec::{
order::{Lsb0, Msb0},
vec::BitVec,
};
assert_format::<crate::Bits>(StoreFormat::U8, OrderFormat::Lsb0);
assert_format::<BitVec<u8, Lsb0>>(StoreFormat::U8, OrderFormat::Lsb0);
assert_format::<BitVec<u16, Lsb0>>(StoreFormat::U16, OrderFormat::Lsb0);
assert_format::<BitVec<u32, Lsb0>>(StoreFormat::U32, OrderFormat::Lsb0);
assert_format::<BitVec<u64, Lsb0>>(StoreFormat::U64, OrderFormat::Lsb0);
assert_format::<BitVec<u8, Msb0>>(StoreFormat::U8, OrderFormat::Msb0);
assert_format::<BitVec<u16, Msb0>>(StoreFormat::U16, OrderFormat::Msb0);
assert_format::<BitVec<u32, Msb0>>(StoreFormat::U32, OrderFormat::Msb0);
assert_format::<BitVec<u64, Msb0>>(StoreFormat::U64, OrderFormat::Msb0);
}
}