72 lines
2.4 KiB
Rust
72 lines
2.4 KiB
Rust
use std::any::{Any, TypeId, type_name};
|
|
use std::fmt::Debug;
|
|
use std::num::NonZero;
|
|
|
|
use orchid_api_traits::Coding;
|
|
use orchid_base::BoxedIter;
|
|
|
|
use crate::{
|
|
AtomOps, AtomTypeId, Atomic, AtomicFeatures, CmdAtom, Fun, Lambda, ReaderAtom, Replier,
|
|
SystemCtor, WriterAtom,
|
|
};
|
|
|
|
/// Description of a system. This is intended to be a ZST storing the static
|
|
/// properties of a [SystemCtor] which should be known to foreign systems
|
|
pub trait SystemCard: Debug + Default + 'static {
|
|
type Ctor: SystemCtor;
|
|
type Req: Coding;
|
|
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomOps>>>;
|
|
}
|
|
|
|
/// Type-erased [SystemCard]
|
|
pub trait DynSystemCard: Any + 'static {
|
|
fn name(&self) -> &'static str;
|
|
/// Atoms explicitly defined by the system card. Do not rely on this for
|
|
/// querying atoms as it doesn't include the general atom types
|
|
fn atoms(&'_ self) -> BoxedIter<'_, Option<Box<dyn AtomOps>>>;
|
|
}
|
|
|
|
impl<T: SystemCard> DynSystemCard for T {
|
|
fn name(&self) -> &'static str { T::Ctor::NAME }
|
|
fn atoms(&'_ self) -> BoxedIter<'_, Option<Box<dyn AtomOps>>> {
|
|
Box::new(Self::atoms().into_iter())
|
|
}
|
|
}
|
|
|
|
impl<T: DynSystemCard + ?Sized> DynSystemCardExt for T {}
|
|
pub(crate) trait DynSystemCardExt: DynSystemCard {
|
|
fn ops_by_tid(&self, tid: TypeId) -> Option<(AtomTypeId, Box<dyn AtomOps>)> {
|
|
(self.atoms().enumerate().map(|(i, o)| (NonZero::new(i as u32 + 1).unwrap(), o)))
|
|
.chain(general_atoms().enumerate().map(|(i, o)| (NonZero::new(!(i as u32)).unwrap(), o)))
|
|
.filter_map(|(i, o)| o.map(|a| (AtomTypeId(i), a)))
|
|
.find(|ent| ent.1.tid() == tid)
|
|
}
|
|
fn ops_by_atid(&self, tid: AtomTypeId) -> Option<Box<dyn AtomOps>> {
|
|
if (u32::from(tid.0) >> (u32::BITS - 1)) & 1 == 1 {
|
|
general_atoms().nth(!u32::from(tid.0) as usize).unwrap()
|
|
} else {
|
|
self.atoms().nth(u32::from(tid.0) as usize - 1).unwrap()
|
|
}
|
|
}
|
|
fn ops<A: Atomic>(&self) -> (AtomTypeId, Box<dyn AtomOps>) {
|
|
self
|
|
.ops_by_tid(TypeId::of::<A>())
|
|
.unwrap_or_else(|| panic!("{} is not an atom in {}", type_name::<A>(), self.name()))
|
|
}
|
|
}
|
|
|
|
/// Atoms supported by this package which may appear in all extensions.
|
|
/// The indices of these are bitwise negated, such that the MSB of an atom index
|
|
/// marks whether it belongs to this package (0) or the importer (1)
|
|
pub(crate) fn general_atoms() -> impl Iterator<Item = Option<Box<dyn AtomOps>>> {
|
|
[
|
|
Some(Fun::ops()),
|
|
Some(Lambda::ops()),
|
|
Some(Replier::ops()),
|
|
Some(CmdAtom::ops()),
|
|
Some(WriterAtom::ops()),
|
|
Some(ReaderAtom::ops()),
|
|
]
|
|
.into_iter()
|
|
}
|