use crate::{
form::PortableForm,
interner::Interner,
prelude::{
fmt::Debug,
vec::Vec,
},
Registry,
Type,
};
use scale::Encode;
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[derive(Clone, Debug, PartialEq, Eq, Encode)]
pub struct PortableRegistry {
types: Vec<PortableType>,
}
impl From<Registry> for PortableRegistry {
fn from(registry: Registry) -> Self {
PortableRegistry {
types: registry
.types()
.map(|(k, v)| {
PortableType {
id: k.id(),
ty: v.clone(),
}
})
.collect::<Vec<_>>(),
}
}
}
impl PortableRegistry {
pub fn resolve(&self, id: u32) -> Option<&Type<PortableForm>> {
self.types.get(id as usize).map(|ty| ty.ty())
}
pub fn types(&self) -> &[PortableType] {
&self.types
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[derive(Clone, Debug, PartialEq, Eq, Encode)]
pub struct PortableType {
#[codec(compact)]
id: u32,
#[cfg_attr(feature = "serde", serde(rename = "type"))]
ty: Type<PortableForm>,
}
impl PortableType {
pub fn new(id: u32, ty: Type<PortableForm>) -> Self {
Self { id, ty }
}
pub fn id(&self) -> u32 {
self.id
}
pub fn ty(&self) -> &Type<PortableForm> {
&self.ty
}
}
#[derive(Debug, Default)]
pub struct PortableRegistryBuilder {
types: Interner<Type<PortableForm>>,
}
impl PortableRegistryBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn register_type(&mut self, ty: Type<PortableForm>) -> u32 {
self.types.intern_or_get(ty).1.into_untracked().id()
}
pub fn next_type_id(&self) -> u32 {
self.types.elements().len() as u32
}
pub fn get(&self, id: u32) -> Option<&Type<PortableForm>> {
self.types.elements().get(id as usize)
}
pub fn finish(&self) -> PortableRegistry {
let types = self
.types
.elements()
.iter()
.enumerate()
.map(|(i, ty)| {
PortableType {
id: i as u32,
ty: ty.clone(),
}
})
.collect();
PortableRegistry { types }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
build::*,
prelude::vec,
*,
};
#[test]
fn type_ids_are_sequential() {
let mut registry = Registry::new();
registry.register_type(&MetaType::new::<u32>());
registry.register_type(&MetaType::new::<bool>());
registry.register_type(&MetaType::new::<Option<(u32, bool)>>());
let readonly: PortableRegistry = registry.into();
assert_eq!(4, readonly.types().len());
for (expected, ty) in readonly.types().iter().enumerate() {
assert_eq!(expected as u32, ty.id());
}
}
#[test]
fn construct_portable_registry() {
let mut builder = PortableRegistryBuilder::new();
let u32_type = Type::new(Path::default(), vec![], TypeDefPrimitive::U32, vec![]);
let u32_type_id = builder.register_type(u32_type.clone());
let vec_u32_type = Type::new(
Path::default(),
vec![],
TypeDefSequence::new(u32_type_id.into()),
vec![],
);
let vec_u32_type_id = builder.register_type(vec_u32_type.clone());
let self_referential_type_id = builder.next_type_id();
let composite_type = Type::builder_portable()
.path(Path::from_segments_unchecked(["MyStruct".into()]))
.composite(
Fields::named()
.field_portable(|f| f.name("primitive".into()).ty(u32_type_id))
.field_portable(|f| f.name("vec_of_u32".into()).ty(vec_u32_type_id))
.field_portable(|f| {
f.name("self_referential".into())
.ty(self_referential_type_id)
}),
);
let composite_type_id = builder.register_type(composite_type.clone());
assert_eq!(self_referential_type_id, composite_type_id);
assert_eq!(builder.get(u32_type_id).unwrap(), &u32_type);
assert_eq!(builder.get(vec_u32_type_id).unwrap(), &vec_u32_type);
assert_eq!(builder.get(composite_type_id).unwrap(), &composite_type);
let registry = builder.finish();
assert_eq!(Some(&u32_type), registry.resolve(u32_type_id));
assert_eq!(Some(&vec_u32_type), registry.resolve(vec_u32_type_id));
assert_eq!(Some(&composite_type), registry.resolve(composite_type_id));
}
}