use crate::{
arg_err_noloc,
combine::{Parser, parser},
common_traits::Verify,
context::{Context, collect_deduped_interface_verifiers},
deps::{hash::FxHashMap, sync::LazyLock},
dialect::{Dialect, DialectName},
identifier::Identifier,
impl_printable_for_display, input_err,
irfmt::parsers::spaced,
location::Located,
parsable::{Parsable, ParseResult, StateStream},
printable::{self, Printable},
result::Result,
storage_uniquer::TypeValueHash,
};
use alloc::{
boxed::Box,
string::{String, ToString},
vec::Vec,
};
use core::{
cell::{Ref, RefCell, RefMut},
fmt::{Debug, Display},
hash::{Hash, Hasher},
marker::PhantomData,
ops::Deref,
};
use downcast_rs::{Downcast, impl_downcast};
use thiserror::Error;
pub trait Type: Printable + Verify + Downcast + Sync + Send + Debug {
fn hash_type(&self) -> TypeValueHash;
fn eq_type(&self, other: &dyn Type) -> bool;
fn get_self_handle(&self, ctx: &Context) -> TypeHandle {
let is = |other: &TypeObj| self.eq_type(&**other.0.borrow());
let idx = ctx
.type_store
.get(self.hash_type(), &is)
.expect("Unregistered type object in existence");
TypeHandle(idx)
}
fn register_instance(t: Self, ctx: &Context) -> TypedHandle<Self>
where
Self: Sized,
{
let hash = t.hash_type();
let idx = ctx.type_store.get_or_create_unique(
TypeObj(RefCell::new(Box::new(t))),
hash,
&TypeObj::eq,
);
TypedHandle(TypeHandle(idx), PhantomData::<Self>)
}
fn get_instance(t: Self, ctx: &Context) -> Option<TypedHandle<Self>>
where
Self: Sized,
{
let is = |other: &TypeObj| t.eq_type(&**other.0.borrow());
ctx.type_store
.get(t.hash_type(), &is)
.map(|idx| TypedHandle(TypeHandle(idx), PhantomData::<Self>))
}
fn get_type_id(&self) -> TypeId;
fn get_type_id_static() -> TypeId
where
Self: Sized;
#[doc(hidden)]
fn verify_interfaces(&self, ctx: &Context) -> Result<()>;
fn register(ctx: &mut Context)
where
Self: Sized + Parsable<Arg = (), Parsed = TypedHandle<Self>>,
{
let ptr_parser: TypeParserFn = Box::new(|&()| {
combine::parser(move |parsable_state: &mut StateStream<'_>| {
Self::parse(parsable_state, ())
.map(|(typtr, r)| -> (TypeHandle, _) { (typtr.to_handle(), r) })
})
.boxed()
});
let typeid = Self::get_type_id_static();
Dialect::register(ctx, &typeid.dialect.clone()).add_type(typeid, ptr_parser);
}
}
impl_downcast!(Type);
pub(crate) type TypeParserFn = Box<
for<'a> fn(
&'a (),
)
-> Box<dyn Parser<StateStream<'a>, Output = TypeHandle, PartialState = ()> + 'a>,
>;
pub trait Typed {
fn get_type(&self, ctx: &Context) -> TypeHandle;
}
impl Typed for TypeHandle {
fn get_type(&self, _ctx: &Context) -> TypeHandle {
*self
}
}
impl Typed for dyn Type {
fn get_type(&self, ctx: &Context) -> TypeHandle {
self.get_self_handle(ctx)
}
}
impl<T: Typed + ?Sized> Typed for &T {
fn get_type(&self, ctx: &Context) -> TypeHandle {
(*self).get_type(ctx)
}
}
impl<T: Typed + ?Sized> Typed for &mut T {
fn get_type(&self, ctx: &Context) -> TypeHandle {
(**self).get_type(ctx)
}
}
impl<T: Typed + ?Sized> Typed for Box<T> {
fn get_type(&self, ctx: &Context) -> TypeHandle {
(**self).get_type(ctx)
}
}
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct TypeName(Identifier);
impl TypeName {
pub fn new(name: &str) -> TypeName {
TypeName(name.try_into().expect("Invalid Identifier for TypeName"))
}
}
impl Deref for TypeName {
type Target = Identifier;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl_printable_for_display!(TypeName);
impl Display for TypeName {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Parsable for TypeName {
type Arg = ();
type Parsed = TypeName;
fn parse<'a>(
state_stream: &mut crate::parsable::StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed>
where
Self: Sized,
{
Identifier::parser(())
.map(|name| TypeName::new(&name))
.parse_stream(state_stream)
.into()
}
}
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct TypeId {
pub dialect: DialectName,
pub name: TypeName,
}
impl Parsable for TypeId {
type Arg = ();
type Parsed = TypeId;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed>
where
Self: Sized,
{
let mut parser = DialectName::parser(())
.skip(parser::char::char('.'))
.and(TypeName::parser(()))
.map(|(dialect, name)| TypeId { dialect, name });
parser.parse_stream(state_stream).into()
}
}
impl_printable_for_display!(TypeId);
impl Display for TypeId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}.{}", self.dialect, self.name)
}
}
pub(crate) struct TypeObj(RefCell<Box<dyn Type>>);
impl PartialEq for TypeObj {
fn eq(&self, other: &Self) -> bool {
self.0.borrow().eq_type(&**other.0.borrow())
}
}
impl Eq for TypeObj {}
impl Hash for TypeObj {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(&u64::from(self.0.borrow().hash_type()).to_ne_bytes())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeHandle(usize);
impl TypeHandle {
pub fn deref<'a>(&self, ctx: &'a Context) -> Ref<'a, dyn Type> {
Ref::map(
ctx.type_store.unique_store.get(self.0).unwrap().0.borrow(),
|t| &**t,
)
}
pub fn deref_mut<'a>(&self, ctx: &'a Context) -> RefMut<'a, dyn Type> {
RefMut::map(
ctx.type_store
.unique_store
.get(self.0)
.unwrap()
.0
.borrow_mut(),
|t| &mut **t,
)
}
}
impl Printable for TypeHandle {
fn fmt(
&self,
ctx: &Context,
state: &printable::State,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
write!(f, "{} ", self.deref(ctx).get_type_id())?;
Printable::fmt(&*self.deref(ctx), ctx, state, f)
}
}
impl Verify for TypeHandle {
fn verify(&self, ctx: &Context) -> Result<()> {
verify_type(&*self.deref(ctx), ctx)
}
}
impl Parsable for TypeHandle {
type Arg = ();
type Parsed = Self;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
let loc = state_stream.loc();
let type_id_parser = spaced(TypeId::parser(()));
let mut type_parser = type_id_parser.then(move |type_id: TypeId| {
let loc = loc.clone();
combine::parser(move |parsable_state: &mut StateStream<'a>| {
let state = &parsable_state.state;
let dialect = state
.ctx
.dialects
.get(&type_id.dialect)
.expect("Dialect name parsed but dialect isn't registered");
let Some(type_parser) = dialect.types.get(&type_id) else {
input_err!(loc.clone(), "Unregistered type {}", type_id.disp(state.ctx))?
};
type_parser(&()).parse_stream(parsable_state).into()
})
});
type_parser.parse_stream(state_stream).into_result()
}
}
pub fn verify_type(ty: &dyn Type, ctx: &Context) -> Result<()> {
ty.verify_interfaces(ctx)?;
Verify::verify(ty, ctx)
}
impl Verify for TypeObj {
fn verify(&self, ctx: &Context) -> Result<()> {
verify_type(self.0.borrow().as_ref(), ctx)
}
}
#[derive(Debug)]
pub struct TypedHandle<T: Type>(TypeHandle, PhantomData<T>);
#[derive(Error, Debug)]
#[error("TypedHandle mismatch: Constructing {expected} but provided {provided}")]
pub struct TypedHandleErr {
pub expected: String,
pub provided: String,
}
impl<T: Type> TypedHandle<T> {
pub fn deref<'a>(&self, ctx: &'a Context) -> Ref<'a, T> {
Ref::map(self.0.deref(ctx), |t| {
t.downcast_ref::<T>()
.expect("Type mistmatch, inconsistent TypedHandle")
})
}
pub fn from_handle(handle: TypeHandle, ctx: &Context) -> Result<TypedHandle<T>> {
if handle.deref(ctx).is::<T>() {
Ok(TypedHandle(handle, PhantomData::<T>))
} else {
arg_err_noloc!(TypedHandleErr {
expected: T::get_type_id_static().disp(ctx).to_string(),
provided: handle.disp(ctx).to_string()
})
}
}
pub fn to_handle(&self) -> TypeHandle {
self.0
}
}
impl<T: Type> From<TypedHandle<T>> for TypeHandle {
fn from(value: TypedHandle<T>) -> Self {
value.to_handle()
}
}
impl<T: Type> Clone for TypedHandle<T> {
fn clone(&self) -> TypedHandle<T> {
*self
}
}
impl<T: Type> Copy for TypedHandle<T> {}
impl<T: Type> PartialEq for TypedHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: Type> Eq for TypedHandle<T> {}
impl<T: Type> Hash for TypedHandle<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T: Type> Printable for TypedHandle<T> {
fn fmt(
&self,
ctx: &Context,
state: &printable::State,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
Printable::fmt(&self.0, ctx, state, f)
}
}
impl<T: Type + Parsable<Arg = (), Parsed = TypedHandle<T>>> Parsable for TypedHandle<T> {
type Arg = ();
type Parsed = Self;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
let loc = state_stream.loc();
spaced(TypeId::parser(()))
.then(move |type_id| {
let loc = loc.clone();
combine::parser(move |parsable_state: &mut StateStream<'a>| {
if type_id != T::get_type_id_static() {
input_err!(
loc.clone(),
"Expected type {}, but found {}",
T::get_type_id_static().disp(parsable_state.state.ctx),
type_id.disp(parsable_state.state.ctx)
)?
}
T::parser(arg).parse_stream(parsable_state).into()
})
})
.parse_stream(state_stream)
.into_result()
}
}
impl<T: Type> Verify for TypedHandle<T> {
fn verify(&self, ctx: &Context) -> Result<()> {
self.0.deref(ctx).verify(ctx)
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` not a type interface.",
label = "If `{Self}` is a trait, annotate it with #[type_interface] to be able to cast to it from a `&dyn Type`",
note = "If you want to cast to a concrete `Type`, use `downcast_ref` instead."
)]
pub trait TypeInterfaceMarker {}
pub fn type_cast<T: ?Sized + TypeInterfaceMarker + 'static>(ty: &dyn Type) -> Option<&T> {
crate::utils::trait_cast::any_to_trait::<T>(ty.as_any())
}
pub fn type_impls<T: ?Sized + TypeInterfaceMarker + 'static>(ty: &dyn Type) -> bool {
type_cast::<T>(ty).is_some()
}
pub type TypeInterfaceVerifier = fn(&dyn Type, &Context) -> Result<()>;
pub type TypeInterfaceAllVerifiers = fn() -> Vec<TypeInterfaceVerifier>;
#[doc(hidden)]
type TypeInterfaceVerifierInfo = (core::any::TypeId, TypeInterfaceAllVerifiers);
#[cfg(not(target_family = "wasm"))]
pub mod statics {
use super::*;
#[::pliron::linkme::distributed_slice]
pub static TYPE_INTERFACE_VERIFIERS: [LazyLock<TypeInterfaceVerifierInfo>] = [..];
pub fn get_type_interface_verifiers()
-> impl Iterator<Item = &'static LazyLock<TypeInterfaceVerifierInfo>> {
TYPE_INTERFACE_VERIFIERS.iter()
}
}
#[cfg(target_family = "wasm")]
pub mod statics {
use super::*;
use crate::utils::inventory::LazyLockWrapper;
::pliron::inventory::collect!(LazyLockWrapper<TypeInterfaceVerifierInfo>);
pub fn get_type_interface_verifiers()
-> impl Iterator<Item = &'static LazyLock<TypeInterfaceVerifierInfo>> {
::pliron::inventory::iter::<LazyLockWrapper<TypeInterfaceVerifierInfo>>().map(|llw| llw.0)
}
}
pub use statics::*;
#[doc(hidden)]
pub static TYPE_INTERFACE_VERIFIERS_MAP: LazyLock<
FxHashMap<core::any::TypeId, Vec<TypeInterfaceVerifier>>,
> = LazyLock::new(|| collect_deduped_interface_verifiers(get_type_interface_verifiers()));