diff --git a/crates/tytix-core/src/actor.rs b/crates/tytix-core/src/actor.rs deleted file mode 100644 index 1b9391f..0000000 --- a/crates/tytix-core/src/actor.rs +++ /dev/null @@ -1,147 +0,0 @@ -use std::any::Any; -use std::marker::PhantomData; -use std::pin::Pin; - -use crate::InternalMessage; -use crate::IsContainedInBundle; -use crate::Message; -use crate::MessageBundle; - -pub trait Actor: Any -where - Self: ActorHandler, -{ - type HandledMessages: MessageBundle; -} - -pub trait IntoActorHandle { - fn into_actor_handle(self) -> ActorHandle; -} - -impl IntoActorHandle for A { - fn into_actor_handle(self) -> ActorHandle { - ActorHandle::new(self) - } -} - -pub trait Handle { - fn handle(&mut self, message: M) -> impl Future>; -} - -pub trait ActorHandler: Any { - fn handle_message( - &mut self, - message: InternalMessage, - ) -> impl Future>; -} - -macro_rules! impl_actor_handle { - ( $($ty:ident),* ) => { - impl ActorHandler<($($ty,)*)> for ACTOR - where - ACTOR: Actor, - $( ACTOR: Handle<$ty>, )* - $( $ty: Message, )* - { - fn handle_message( - &mut self, - msg: InternalMessage, - ) -> impl Future> { - - #[allow(unused_variables)] - async { - $( - let msg = match msg.into_inner::<$ty>() { - Ok(msg) => { - return >::handle(self, msg).await.map(InternalMessage::new); - } - Err(msg) => msg, - }; - )* - - Err(anyhow::anyhow!("Could not handle message")) - - } - } - - } - }; -} - -all_the_tuples!(impl_actor_handle); - -pub struct ActorHandle { - actor: Box, - #[allow(clippy::type_complexity)] - handle: for<'a> fn( - &'a mut dyn Any, - msg: InternalMessage, - ) -> Pin> + 'a>>, - _pd: PhantomData, -} - -impl ActorHandle { - pub fn new>(actor: A) -> ActorHandle { - ActorHandle { - actor: Box::new(actor), - handle: |actor, msg| { - let actor: &mut A = actor.downcast_mut().unwrap(); - - Box::pin(actor.handle_message(msg)) - }, - - _pd: PhantomData, - } - } - - pub async fn handle>( - &mut self, - message: M, - ) -> anyhow::Result { - const { - let true = >::IS_CONTAINED else { - panic!("Message is not contained in MessageBundle",); - }; - } - - (self.handle)(self.actor.as_mut(), InternalMessage::new(message)) - .await - .map(|msg| match msg.into_inner::() { - Ok(t) => t, - Err(msg) => panic!("Could not process reply of type: {}", msg.type_name()), - }) - } -} - -#[cfg(test)] -mod tests { - use macro_rules_attribute::apply; - use smol_macros::test; - - use super::*; - - struct Foo; - - impl Message for Foo { - type Reply = (); - } - - struct FActor; - - impl Actor for FActor { - type HandledMessages = (Foo,); - } - - impl Handle for FActor { - async fn handle(&mut self, _message: Foo) -> anyhow::Result<::Reply> { - Ok(()) - } - } - - #[apply(test!)] - async fn test_name() { - let mut actor = FActor.into_actor_handle(); - - actor.handle(Foo).await.unwrap(); - } -} diff --git a/crates/tytix-core/src/address.rs b/crates/tytix-core/src/address.rs deleted file mode 100644 index c80671b..0000000 --- a/crates/tytix-core/src/address.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::any::Any; -use std::marker::PhantomData; -use std::pin::Pin; - -use crate::InternalMessage; -use crate::IsContainedInBundle; -use crate::Message; -use crate::MessageBundle; - -pub trait Address { - fn send(&mut self, message: M) -> impl Future>; -} - -pub struct BoxedAddress { - addr: Box, - #[allow(clippy::type_complexity)] - send: for<'a> fn( - &'a mut dyn Any, - InternalMessage, - ) -> Pin> + 'a>>, - _pd: PhantomData, -} - -impl BoxedAddress { - pub fn new(addr: IMH) -> Self - where - IMH: InternalMessageHandler + 'static, - { - BoxedAddress { - addr: Box::new(addr), - send: |addr, msg| { - let addr: &mut IMH = addr.downcast_mut().unwrap(); - - Box::pin(addr.handle_message(msg)) - }, - _pd: PhantomData, - } - } -} - -impl InternalMessageHandler for BoxedAddress -where - MB: MessageBundle, -{ - type HandledMessages = MB; - fn handle_message( - &mut self, - msg: InternalMessage, - ) -> impl Future> { - (self.send)(self.addr.as_mut(), msg) - } -} - -pub trait InternalMessageHandler { - type HandledMessages: MessageBundle; - fn handle_message( - &mut self, - msg: InternalMessage, - ) -> impl Future>; -} - -impl Address for IMH -where - IMH: InternalMessageHandler, -{ - fn send(&mut self, message: M) -> impl Future> { - const { - let true = >::IS_CONTAINED else { - panic!("Message is not contained in MessageBundle",); - }; - } - - let message = self.handle_message(InternalMessage::new(message)); - - async { - message.await.and_then(|msg| { - msg.into_inner::().map_err(|e| { - anyhow::anyhow!( - "Expected a {}, but got a {}", - std::any::type_name::(), - e.type_name() - ) - }) - }) - } - } -} diff --git a/crates/tytix-core/src/lib.rs b/crates/tytix-core/src/lib.rs index 3a8bd5f..7651dee 100644 --- a/crates/tytix-core/src/lib.rs +++ b/crates/tytix-core/src/lib.rs @@ -1,21 +1,114 @@ #![feature(const_cmp)] #![feature(const_trait_impl)] -#[macro_use] -mod macros; -pub mod address; -pub mod message; -pub mod actor; - +use std::any::Any; use std::any::TypeId; -pub use address::Address; -pub use address::BoxedAddress; -pub use address::InternalMessageHandler; pub use anyhow; -pub use message::InternalMessage; -pub use message::Message; -pub use message::MessageBundle; + +pub trait Message: Send + Any { + type Reply: Send + Any; +} + +pub trait MessageIdentifier { + const IDENT: BundleChain; +} + +impl MessageIdentifier for M { + const IDENT: BundleChain = BundleChain::of::(); +} + +pub struct InternalMessage { + value: Box, + name: &'static str, +} + +impl InternalMessage { + pub fn new(message: M) -> InternalMessage { + InternalMessage { + value: Box::new(message), + name: std::any::type_name::(), + } + } + + pub fn into_inner(self) -> Result { + self.value + .downcast() + .map(|v| *v) + .map_err(|value| InternalMessage { + value, + name: self.name, + }) + } + + pub fn as_ref(&self) -> Option<&M> { + self.value.downcast_ref() + } + + pub fn type_name(&self) -> &'static str { + self.name + } + + pub fn type_id(&self) -> TypeId { + self.value.as_ref().type_id() + } +} + +pub trait Address { + fn send(&mut self, message: M) -> impl Future>; +} + +pub trait InternalMessageHandler { + type HandledMessages: MessageBundle; + fn handle_message( + &mut self, + msg: InternalMessage, + ) -> impl Future>; +} + +impl Address for IMH +where + IMH: InternalMessageHandler, +{ + fn send(&mut self, message: M) -> impl Future> { + const { + let true = >::IS_CONTAINED else { + panic!("Message is not contained in MessageBundle",); + }; + } + + let message = self.handle_message(InternalMessage::new(message)); + + async { + message.await.and_then(|msg| { + msg.into_inner::().map_err(|e| { + anyhow::anyhow!( + "Expected a {}, but got a {}", + std::any::type_name::(), + e.type_name() + ) + }) + }) + } + } +} + +pub trait MessageReceiver {} + +pub trait MessageBundle { + const IDS: BundleChain; +} + +impl MessageBundle for () { + const IDS: BundleChain = BundleChain { + next: None, + op: BundleOp::Remove(TypeId::of::<()>()), + }; +} + +impl MessageBundle for (M,) { + const IDS: BundleChain = BundleChain::of::(); +} #[derive(Debug, Clone, Copy)] pub struct BundleChain { @@ -24,21 +117,13 @@ pub struct BundleChain { } #[derive(Debug, Clone, Copy)] -enum BundleOp { +pub enum BundleOp { Add(TypeId), Remove(TypeId), Chain(&'static BundleChain), - None, } impl BundleChain { - pub const fn empty() -> BundleChain { - BundleChain { - op: BundleOp::None, - next: None, - } - } - pub const fn of() -> BundleChain { BundleChain { op: BundleOp::Add(TypeId::of::()), @@ -50,40 +135,6 @@ impl BundleChain { check_is_contained(self, id) } - pub const fn is_subset_of(&self, ids: &BundleChain) -> bool { - let mut current = self; - - loop { - match current.op { - BundleOp::Add(type_id) => { - if !ids.contains(type_id) { - return false; - } - } - BundleOp::Remove(..) => (), - BundleOp::Chain(bundle_chain) => { - let chain_result = bundle_chain.is_subset_of(ids); - let own_result = if let Some(bc) = self.next { - bc.is_subset_of(ids) - } else { - true - }; - - return chain_result && own_result; - } - BundleOp::None => (), - } - - if let Some(next) = current.next { - current = next; - } else { - break; - }; - } - - true - } - pub const fn with(&'static self) -> BundleChain { let to_add = TypeId::of::(); BundleChain { @@ -108,6 +159,24 @@ impl BundleChain { } } +impl MessageBundle for (A, B) +where + A: Message, + B: Message, +{ + const IDS: BundleChain = BundleChain::of::().with::(); +} + +impl MessageBundle for (A, B, C, D) +where + A: Message, + B: Message, + C: Message, + D: Message, +{ + const IDS: BundleChain = BundleChain::of::().with::().with::().with::(); +} + pub trait IsContainedInBundle { const IS_CONTAINED: bool; } @@ -117,7 +186,7 @@ where M: Message, MB: MessageBundle, { - const IS_CONTAINED: bool = check_is_contained(&MB::CHAIN, TypeId::of::()); + const IS_CONTAINED: bool = check_is_contained(&MB::IDS, TypeId::of::()); } const fn check_is_contained(ids: &BundleChain, id: TypeId) -> bool { @@ -137,7 +206,6 @@ const fn check_is_contained(ids: &BundleChain, id: TypeId) -> bool { return true; } } - BundleOp::None => (), } if let Some(next) = ids.next { @@ -201,16 +269,6 @@ mod tests { )); } - #[test] - fn check_subset() { - const CHAIN: BundleChain = BundleChain::of::().join(&BundleChain::of::()); - const SUB: BundleChain = BundleChain::of::().with::(); - - assert!(SUB.is_subset_of(&CHAIN)); - - assert!(!BundleChain::of::().is_subset_of(&CHAIN)); - } - #[apply(test!)] async fn check_sending_messages() { struct Sender; diff --git a/crates/tytix-core/src/macros.rs b/crates/tytix-core/src/macros.rs deleted file mode 100644 index 914ce3d..0000000 --- a/crates/tytix-core/src/macros.rs +++ /dev/null @@ -1,43 +0,0 @@ -#[rustfmt::skip] -macro_rules! all_the_tuples { - ($name:ident) => { - $name!(M1); - $name!(M1, M2); - $name!(M1, M2, M3); - $name!(M1, M2, M3, M4); - $name!(M1, M2, M3, M4, M5); - $name!(M1, M2, M3, M4, M5, M6); - $name!(M1, M2, M3, M4, M5, M6, M7); - $name!(M1, M2, M3, M4, M5, M6, M7, M8); - $name!(M1, M2, M3, M4, M5, M6, M7, M8, M9); - $name!(M1, M2, M3, M4, M5, M6, M7, M8, M9, M10); - $name!(M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11); - $name!(M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12); - $name!(M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13); - $name!(M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14); - $name!(M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15); - $name!(M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16); - }; -} - -#[rustfmt::skip] -macro_rules! all_the_tuples_special_first { - ($name:ident) => { - $name!([], M1); - $name!([M1], M2); - $name!([M1, M2], M3); - $name!([M1, M2, M3], M4); - $name!([M1, M2, M3, M4], M5); - $name!([M1, M2, M3, M4, M5], M6); - $name!([M1, M2, M3, M4, M5, M6], M7); - $name!([M1, M2, M3, M4, M5, M6, M7], M8); - $name!([M1, M2, M3, M4, M5, M6, M7, M8], M9); - $name!([M1, M2, M3, M4, M5, M6, M7, M8, M9], M10); - $name!([M1, M2, M3, M4, M5, M6, M7, M8, M9, M10], M11); - $name!([M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11], M12); - $name!([M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12], M13); - $name!([M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13], M14); - $name!([M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14], M15); - $name!([M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15], M16); - }; -} diff --git a/crates/tytix-core/src/message.rs b/crates/tytix-core/src/message.rs deleted file mode 100644 index e91d29f..0000000 --- a/crates/tytix-core/src/message.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::any::Any; -use std::any::TypeId; - -use crate::BundleChain; - -pub trait Message: Send + Any { - type Reply: Send + Any; -} - -pub struct InternalMessage { - value: Box, - name: &'static str, -} - -impl InternalMessage { - pub fn new(message: M) -> InternalMessage { - InternalMessage { - value: Box::new(message), - name: std::any::type_name::(), - } - } - - pub fn into_inner(self) -> Result { - self.value - .downcast() - .map(|v| *v) - .map_err(|value| InternalMessage { - value, - name: self.name, - }) - } - - pub fn as_ref(&self) -> Option<&M> { - self.value.downcast_ref() - } - - pub fn type_name(&self) -> &'static str { - self.name - } - - pub fn type_id(&self) -> TypeId { - self.value.as_ref().type_id() - } -} - -pub trait MessageBundle { - const CHAIN: BundleChain; -} - -impl MessageBundle for () { - const CHAIN: BundleChain = BundleChain::empty(); -} - -macro_rules! impl_message_bundles { - ( [ $($ty:ident),* ] , $last:ident ) => { - impl<$($ty,)* $last> MessageBundle for ($($ty,)* $last,) - where - $( $ty: Message, )* - $last: Message, - { - const CHAIN: BundleChain = <($($ty,)*) as MessageBundle>::CHAIN.with::<$last>(); - } - }; -} - -all_the_tuples_special_first!(impl_message_bundles); diff --git a/crates/tytix/src/lib.rs b/crates/tytix/src/lib.rs index 523c5df..f1222ef 100644 --- a/crates/tytix/src/lib.rs +++ b/crates/tytix/src/lib.rs @@ -1,7 +1,6 @@ use std::marker::PhantomData; use futures::FutureExt; -use tytix_core::BoxedAddress; use tytix_core::InternalMessage; use tytix_core::InternalMessageHandler; use tytix_core::IsContainedInBundle; @@ -19,29 +18,17 @@ pub trait AddressExt { fn inspect(self, f: F) -> Inspect where - Inspect: InternalMessageHandler, + F: Fn(&M) -> U, + M: Message + IsContainedInBundle, Self: Sized; fn join(self, o: Other) -> Joined where Joined: InternalMessageHandler, Self: Sized; - - fn simplify(self) -> SimpleAddress - where - SimpleAddress: InternalMessageHandler, - Self: Sized; - - fn boxed(self) -> BoxedAddress - where - BoxedAddress: InternalMessageHandler; } -impl AddressExt for A -where - MB: MessageBundle, - A: InternalMessageHandler + 'static, -{ +impl> AddressExt for A { fn map(self, f: F, r: RF) -> MappedMessage where MappedMessage: InternalMessageHandler, @@ -57,9 +44,16 @@ where fn inspect(self, f: F) -> Inspect where - Inspect: InternalMessageHandler, + F: Fn(&M) -> U, Self: Sized, + M: Message + IsContainedInBundle, { + const { + let true = >::IS_CONTAINED else { + panic!("Message is not contained in MessageBundle",); + }; + } + Inspect { address: self, func: f, @@ -77,47 +71,6 @@ where right: o, } } - - fn simplify(self) -> SimpleAddress - where - SimpleAddress: InternalMessageHandler, - Self: Sized, - { - SimpleAddress { - inner: self, - _pd: PhantomData, - } - } - - fn boxed(self) -> BoxedAddress { - BoxedAddress::new(self) - } -} - -pub struct SimpleAddress { - inner: A, - _pd: PhantomData, -} - -impl InternalMessageHandler for SimpleAddress -where - SMB: MessageBundle, - MB: MessageBundle, - A: InternalMessageHandler, -{ - type HandledMessages = SMB; - - fn handle_message( - &mut self, - msg: InternalMessage, - ) -> impl Future> { - const { - let true = SMB::CHAIN.is_subset_of(&MB::CHAIN) else { - panic!("Message is not contained in MessageBundle",); - }; - } - self.inner.handle_message(msg) - } } pub struct Joined { @@ -134,8 +87,7 @@ where L: MessageBundle, R: MessageBundle, { - const CHAIN: tytix_core::BundleChain = - ::CHAIN.join(&::CHAIN); + const IDS: tytix_core::BundleChain = ::IDS.join(&::IDS); } impl InternalMessageHandler for Joined @@ -148,7 +100,7 @@ where async fn handle_message(&mut self, msg: InternalMessage) -> anyhow::Result { let message_id = msg.type_id(); - if L::HandledMessages::CHAIN.contains(message_id) { + if L::HandledMessages::IDS.contains(message_id) { self.left.handle_message(msg).await } else { self.right.handle_message(msg).await @@ -196,7 +148,7 @@ where M: Message, R: Message + IsContainedInBundle, { - const CHAIN: tytix_core::BundleChain = MB::CHAIN.without::().with::(); + const IDS: tytix_core::BundleChain = MB::IDS.without::().with::(); } impl InternalMessageHandler for MappedMessage @@ -267,9 +219,9 @@ mod tests { type Reply = usize; } - struct FooBarAddress; + struct SimpleAddress; - impl InternalMessageHandler for FooBarAddress { + impl InternalMessageHandler for SimpleAddress { type HandledMessages = (Foo, Bar); async fn handle_message( @@ -301,7 +253,7 @@ mod tests { async fn check_mapping() { static MSG: OnceLock = OnceLock::new(); - let mut sa = FooBarAddress.map( + let mut sa = SimpleAddress.map( |_b: Bar| { let _ = MSG.set(true); async { Foo } @@ -318,7 +270,7 @@ mod tests { async fn check_inspect() { static MSG: OnceLock = OnceLock::new(); - let mut sa = FooBarAddress.inspect(|_b: &Bar| { + let mut sa = SimpleAddress.inspect(|_b: &Bar| { let _ = MSG.set(true); async {} }); @@ -333,11 +285,11 @@ mod tests { } #[apply(test!)] - async fn check_simplify() { + async fn check_join() { static MSG_SA: OnceLock = OnceLock::new(); static MSG_ZAP: OnceLock = OnceLock::new(); - let sa = FooBarAddress.inspect(|_b: &Bar| { + let sa = SimpleAddress.inspect(|_b: &Bar| { MSG_SA.set(true).unwrap(); async {} }); @@ -356,42 +308,4 @@ mod tests { MSG_ZAP.get().expect("The message was NOT inspected!"); } - - #[apply(test!)] - async fn check_join() { - static MSG_SA: OnceLock = OnceLock::new(); - - let sa = FooBarAddress.inspect(|_b: &Bar| { - MSG_SA.set(true).unwrap(); - async {} - }); - - let zap = ZapAddress.join(ZapAddress).join(ZapAddress); - - let joined = sa.join(zap); - - let mut simple = joined.simplify::<(Foo, Bar, Zap)>(); - - simple.send(Bar).await.unwrap(); - - MSG_SA.get().expect("The message was not :CC inspected!"); - } - - #[apply(test!)] - async fn check_boxed() { - static MSG_SA: OnceLock = OnceLock::new(); - - let sa = FooBarAddress.inspect(|_b: &Bar| { - MSG_SA.set(true).unwrap(); - async {} - }); - - let zap = ZapAddress.join(ZapAddress).join(ZapAddress); - - let mut boxed = zap.join(sa).simplify::<(Bar, Zap, Foo)>().boxed(); - - boxed.send(Bar).await.unwrap(); - - MSG_SA.get().expect("The message was not :CC inspected!"); - } }