use crate::{
form::Form,
prelude::{
any::TypeId,
collections::BTreeMap,
fmt::Debug,
vec::Vec,
},
};
use crate::{
form::PortableForm,
interner::{
Interner,
UntrackedSymbol,
},
meta_type::MetaType,
Type,
};
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<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<_>>()
}
pub fn types(
&self,
) -> impl Iterator<Item = (&UntrackedSymbol<TypeId>, &Type<PortableForm>)> {
self.types.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
build::Fields,
meta_type,
Path,
TypeDef,
TypeInfo,
};
#[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")
}
}
}