Initial Commit
Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
commit
9ff1cf1bac
12 changed files with 615 additions and 0 deletions
17
crates/tytix-core/Cargo.toml
Normal file
17
crates/tytix-core/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "tytix-core"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
description = "A clear and simple to use actor framework"
|
||||
repository = "https://github.com/TheNeikos/tytix"
|
||||
license = "EUPL-1.2"
|
||||
keywords = []
|
||||
categories = []
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dev-dependencies]
|
||||
235
crates/tytix-core/src/lib.rs
Normal file
235
crates/tytix-core/src/lib.rs
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
#![feature(const_cmp)]
|
||||
#![feature(const_trait_impl)]
|
||||
|
||||
use std::any::Any;
|
||||
use std::any::TypeId;
|
||||
|
||||
pub trait Message: Send + Any {
|
||||
type Reply: Send + Any;
|
||||
}
|
||||
|
||||
pub trait MessageIdentifier {
|
||||
const IDENT: BundleChain;
|
||||
}
|
||||
|
||||
impl<M: Message> MessageIdentifier for M {
|
||||
const IDENT: BundleChain = BundleChain::of::<M>();
|
||||
}
|
||||
|
||||
pub struct InternalMessage(Box<dyn std::any::Any>);
|
||||
|
||||
impl InternalMessage {
|
||||
pub fn new(message: impl Message) -> InternalMessage {
|
||||
InternalMessage(Box::new(message))
|
||||
}
|
||||
|
||||
pub fn into_inner<M: Message>(self) -> Result<M, InternalMessage> {
|
||||
self.0.downcast().map(|v| *v).map_err(InternalMessage)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Address<MB>
|
||||
where
|
||||
MB: MessageBundle,
|
||||
{
|
||||
fn send<M: Message>(&mut self, message: M);
|
||||
}
|
||||
|
||||
pub trait InternalMessageHandler {
|
||||
type HandledMessages: MessageBundle;
|
||||
fn handle_message(&mut self, msg: InternalMessage);
|
||||
}
|
||||
|
||||
impl<MB, IMH> Address<MB> for IMH
|
||||
where
|
||||
MB: MessageBundle,
|
||||
IMH: InternalMessageHandler<HandledMessages = MB>,
|
||||
{
|
||||
fn send<M: Message>(&mut self, message: M) {
|
||||
const {
|
||||
let true = <M as IsContainedInBundle<MB>>::IS_CONTAINED else {
|
||||
panic!("Message is not contained in MessageBundle",);
|
||||
};
|
||||
}
|
||||
|
||||
self.handle_message(InternalMessage(Box::new(message)));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MessageReceiver {}
|
||||
|
||||
pub trait MessageBundle {
|
||||
const IDS: BundleChain;
|
||||
}
|
||||
|
||||
impl MessageBundle for () {
|
||||
const IDS: BundleChain = BundleChain {
|
||||
next: None,
|
||||
op: BundleOp::Remove(TypeId::of::<()>()),
|
||||
};
|
||||
}
|
||||
|
||||
impl<M: Message> MessageBundle for (M,) {
|
||||
const IDS: BundleChain = BundleChain::of::<M>();
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BundleChain {
|
||||
op: BundleOp,
|
||||
next: Option<&'static BundleChain>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum BundleOp {
|
||||
Add(TypeId),
|
||||
Remove(TypeId),
|
||||
}
|
||||
|
||||
impl BundleChain {
|
||||
pub const fn of<M: Message>() -> BundleChain {
|
||||
BundleChain {
|
||||
op: BundleOp::Add(TypeId::of::<M>()),
|
||||
next: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn with<M: Message>(&'static self) -> BundleChain {
|
||||
add_to_chain(self, TypeId::of::<M>())
|
||||
}
|
||||
|
||||
pub const fn without<M: Message>(&'static self) -> BundleChain {
|
||||
remove_from_chain(self, TypeId::of::<M>())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> MessageBundle for (A, B)
|
||||
where
|
||||
A: Message,
|
||||
B: Message,
|
||||
{
|
||||
const IDS: BundleChain = BundleChain::of::<A>().with::<B>();
|
||||
}
|
||||
|
||||
impl<A, B, C, D> MessageBundle for (A, B, C, D)
|
||||
where
|
||||
A: Message,
|
||||
B: Message,
|
||||
C: Message,
|
||||
D: Message,
|
||||
{
|
||||
const IDS: BundleChain = BundleChain::of::<A>().with::<B>().with::<C>().with::<D>();
|
||||
}
|
||||
|
||||
pub trait IsContainedInBundle<MB> {
|
||||
const IS_CONTAINED: bool;
|
||||
}
|
||||
|
||||
impl<M, MB> IsContainedInBundle<MB> for M
|
||||
where
|
||||
M: Message,
|
||||
MB: MessageBundle,
|
||||
{
|
||||
const IS_CONTAINED: bool = check_is_contained(&MB::IDS, TypeId::of::<M>());
|
||||
}
|
||||
|
||||
const fn check_is_contained(ids: &'static BundleChain, id: TypeId) -> bool {
|
||||
match ids.op {
|
||||
BundleOp::Add(added_id) => {
|
||||
if check_type_id_equal(added_id, id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
BundleOp::Remove(removed_id) => {
|
||||
if check_type_id_equal(removed_id, id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(next) = ids.next {
|
||||
check_is_contained(next, id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
const fn check_type_id_equal(left: TypeId, right: TypeId) -> bool {
|
||||
left == right
|
||||
}
|
||||
|
||||
const fn add_to_chain(prev: &'static BundleChain, to_add: TypeId) -> BundleChain {
|
||||
BundleChain {
|
||||
op: BundleOp::Add(to_add),
|
||||
next: Some(prev),
|
||||
}
|
||||
}
|
||||
|
||||
const fn remove_from_chain(prev: &'static BundleChain, to_remove: TypeId) -> BundleChain {
|
||||
BundleChain {
|
||||
op: BundleOp::Remove(to_remove),
|
||||
next: Some(prev),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
struct Foo;
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Message for Foo {
|
||||
type Reply = ();
|
||||
}
|
||||
|
||||
impl Message for Bar {
|
||||
type Reply = ();
|
||||
}
|
||||
|
||||
struct Zap;
|
||||
|
||||
impl Message for Zap {
|
||||
type Reply = ();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_checker() {
|
||||
assert!(check_type_id_equal(
|
||||
TypeId::of::<bool>(),
|
||||
TypeId::of::<bool>()
|
||||
));
|
||||
|
||||
const BUNDLE: BundleChain = BundleChain::of::<Foo>().with::<Zap>();
|
||||
|
||||
assert!(check_is_contained(&BUNDLE, TypeId::of::<Foo>()));
|
||||
assert!(!check_is_contained(&BUNDLE, TypeId::of::<Bar>()));
|
||||
|
||||
const WITHOUT_BUNDLE: BundleChain = BundleChain::of::<Foo>().with::<Zap>().without::<Zap>();
|
||||
|
||||
assert!(!check_is_contained(&WITHOUT_BUNDLE, TypeId::of::<Zap>()));
|
||||
|
||||
const WITHOUT_WITH_BUNDLE: BundleChain =
|
||||
BundleChain::of::<Foo>().without::<Zap>().with::<Zap>();
|
||||
|
||||
assert!(check_is_contained(
|
||||
&WITHOUT_WITH_BUNDLE,
|
||||
TypeId::of::<Zap>()
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_sending_messages() {
|
||||
struct Sender;
|
||||
|
||||
impl InternalMessageHandler for Sender {
|
||||
type HandledMessages = (Foo, Bar);
|
||||
|
||||
fn handle_message(&mut self, _msg: InternalMessage) {}
|
||||
}
|
||||
|
||||
let mut s = Sender;
|
||||
|
||||
s.send(Foo);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue