use crate::prelude::{
any::TypeId,
collections::BTreeMap,
fmt::Debug,
vec::Vec,
};
use crate::{
form::{
Form,
PortableForm,
},
interner::{
Interner,
UntrackedSymbol,
},
meta_type::MetaType,
Type,
};
use scale::Encode;
pub trait IntoPortable {
type Output;
fn into_portable(self, registry: &mut Registry) -> Self::Output;
}
impl IntoPortable for &'static str {
type Output = <PortableForm as Form>::String;
fn into_portable(self, _registry: &mut Registry) -> Self::Output {
self.into()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Registry {
type_table: Interner<TypeId>,
types: BTreeMap<UntrackedSymbol<core::any::TypeId>, Type<PortableForm>>,
}
impl Default for Registry {
fn default() -> Self {
Self::new()
}
}
impl Registry {
pub fn new() -> Self {
Self {
type_table: Interner::new(),
types: BTreeMap::new(),
}
}
fn intern_type_id(&mut self, type_id: TypeId) -> (bool, UntrackedSymbol<TypeId>) {
let (inserted, symbol) = self.type_table.intern_or_get(type_id);
(inserted, symbol.into_untracked())
}
pub fn register_type(&mut self, ty: &MetaType) -> UntrackedSymbol<TypeId> {
let (inserted, symbol) = self.intern_type_id(ty.type_id());
if inserted {
let portable_id = ty.type_info().into_portable(self);
self.types.insert(symbol, portable_id);
}
symbol
}
pub fn register_types<I>(&mut self, iter: I) -> Vec<UntrackedSymbol<TypeId>>
where
I: IntoIterator<Item = MetaType>,
{
iter.into_iter()
.map(|i| self.register_type(&i))
.collect::<Vec<_>>()
}
pub fn map_into_portable<I, T>(&mut self, iter: I) -> Vec<T::Output>
where
I: IntoIterator<Item = T>,
T: IntoPortable,
{
iter.into_iter()
.map(|i| i.into_portable(self))
.collect::<Vec<_>>()
}
}
#[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
.iter()
.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 id(&self) -> u32 {
self.id
}
pub fn ty(&self) -> &Type<PortableForm> {
&self.ty
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
build::Fields,
meta_type,
Path,
TypeDef,
TypeInfo,
};
#[test]
fn readonly_type_ids() {
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 recursive_struct_with_references() {
#[allow(unused)]
struct RecursiveRefs<'a> {
boxed: Box<RecursiveRefs<'a>>,
reference: &'a RecursiveRefs<'a>,
mutable_reference: &'a mut RecursiveRefs<'a>,
}
impl TypeInfo for RecursiveRefs<'static> {
type Identity = Self;
fn type_info() -> Type {
Type::builder()
.path(Path::new("RecursiveRefs", module_path!()))
.composite(
Fields::named()
.field(|f| {
f.ty::<Box<RecursiveRefs>>()
.name("boxed")
.type_name("Box < RecursiveRefs >")
})
.field(|f| {
f.ty::<&'static RecursiveRefs<'static>>()
.name("reference")
.type_name("&RecursiveRefs")
})
.field(|f| {
f.ty::<&'static mut RecursiveRefs<'static>>()
.name("mutable_reference")
.type_name("&mut RecursiveRefs")
}),
)
}
}
let mut registry = Registry::new();
let type_id = registry.register_type(&meta_type::<RecursiveRefs>());
let recursive = registry.types.get(&type_id).unwrap();
if let TypeDef::Composite(composite) = recursive.type_def() {
for field in composite.fields() {
assert_eq!(*field.ty(), type_id)
}
} else {
panic!("Should be a composite type definition")
}
}
}