Compare commits
No commits in common. "023a2a17fc407dd34657b873d7edaea529f78483" and "d1ad9bac7fb8ba1cd1601587ee87a29ab0ccef4d" have entirely different histories.
023a2a17fc
...
d1ad9bac7f
6 changed files with 145 additions and 516 deletions
|
|
@ -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<Self::HandledMessages>,
|
|
||||||
{
|
|
||||||
type HandledMessages: MessageBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait IntoActorHandle<MB> {
|
|
||||||
fn into_actor_handle(self) -> ActorHandle<MB>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Actor> IntoActorHandle<A::HandledMessages> for A {
|
|
||||||
fn into_actor_handle(self) -> ActorHandle<A::HandledMessages> {
|
|
||||||
ActorHandle::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Handle<M: Message> {
|
|
||||||
fn handle(&mut self, message: M) -> impl Future<Output = anyhow::Result<M::Reply>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ActorHandler<MB>: Any {
|
|
||||||
fn handle_message(
|
|
||||||
&mut self,
|
|
||||||
message: InternalMessage,
|
|
||||||
) -> impl Future<Output = anyhow::Result<InternalMessage>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_actor_handle {
|
|
||||||
( $($ty:ident),* ) => {
|
|
||||||
impl<ACTOR, $($ty,)*> ActorHandler<($($ty,)*)> for ACTOR
|
|
||||||
where
|
|
||||||
ACTOR: Actor,
|
|
||||||
$( ACTOR: Handle<$ty>, )*
|
|
||||||
$( $ty: Message, )*
|
|
||||||
{
|
|
||||||
fn handle_message(
|
|
||||||
&mut self,
|
|
||||||
msg: InternalMessage,
|
|
||||||
) -> impl Future<Output = anyhow::Result<InternalMessage>> {
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
async {
|
|
||||||
$(
|
|
||||||
let msg = match msg.into_inner::<$ty>() {
|
|
||||||
Ok(msg) => {
|
|
||||||
return <Self as Handle<$ty>>::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<MB> {
|
|
||||||
actor: Box<dyn Any>,
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
handle: for<'a> fn(
|
|
||||||
&'a mut dyn Any,
|
|
||||||
msg: InternalMessage,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<InternalMessage>> + 'a>>,
|
|
||||||
_pd: PhantomData<fn(MB)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<MB: MessageBundle + 'static> ActorHandle<MB> {
|
|
||||||
pub fn new<A: ActorHandler<MB>>(actor: A) -> ActorHandle<MB> {
|
|
||||||
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<M: Message + IsContainedInBundle<MB>>(
|
|
||||||
&mut self,
|
|
||||||
message: M,
|
|
||||||
) -> anyhow::Result<M::Reply> {
|
|
||||||
const {
|
|
||||||
let true = <M as IsContainedInBundle<MB>>::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::<M::Reply>() {
|
|
||||||
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<Foo> for FActor {
|
|
||||||
async fn handle(&mut self, _message: Foo) -> anyhow::Result<<Foo as Message>::Reply> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[apply(test!)]
|
|
||||||
async fn test_name() {
|
|
||||||
let mut actor = FActor.into_actor_handle();
|
|
||||||
|
|
||||||
actor.handle(Foo).await.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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<MB> {
|
|
||||||
fn send<M: Message>(&mut self, message: M) -> impl Future<Output = anyhow::Result<M::Reply>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BoxedAddress<MB> {
|
|
||||||
addr: Box<dyn Any>,
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
send: for<'a> fn(
|
|
||||||
&'a mut dyn Any,
|
|
||||||
InternalMessage,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<InternalMessage>> + 'a>>,
|
|
||||||
_pd: PhantomData<fn(MB)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<MB> BoxedAddress<MB> {
|
|
||||||
pub fn new<IMH>(addr: IMH) -> Self
|
|
||||||
where
|
|
||||||
IMH: InternalMessageHandler<HandledMessages = MB> + '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<MB> InternalMessageHandler for BoxedAddress<MB>
|
|
||||||
where
|
|
||||||
MB: MessageBundle,
|
|
||||||
{
|
|
||||||
type HandledMessages = MB;
|
|
||||||
fn handle_message(
|
|
||||||
&mut self,
|
|
||||||
msg: InternalMessage,
|
|
||||||
) -> impl Future<Output = anyhow::Result<InternalMessage>> {
|
|
||||||
(self.send)(self.addr.as_mut(), msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait InternalMessageHandler {
|
|
||||||
type HandledMessages: MessageBundle;
|
|
||||||
fn handle_message(
|
|
||||||
&mut self,
|
|
||||||
msg: InternalMessage,
|
|
||||||
) -> impl Future<Output = anyhow::Result<InternalMessage>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<IMH> Address<IMH::HandledMessages> for IMH
|
|
||||||
where
|
|
||||||
IMH: InternalMessageHandler,
|
|
||||||
{
|
|
||||||
fn send<M: Message>(&mut self, message: M) -> impl Future<Output = anyhow::Result<M::Reply>> {
|
|
||||||
const {
|
|
||||||
let true = <M as IsContainedInBundle<IMH::HandledMessages>>::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::<M::Reply>().map_err(|e| {
|
|
||||||
anyhow::anyhow!(
|
|
||||||
"Expected a {}, but got a {}",
|
|
||||||
std::any::type_name::<M::Reply>(),
|
|
||||||
e.type_name()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +1,114 @@
|
||||||
#![feature(const_cmp)]
|
#![feature(const_cmp)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
#[macro_use]
|
use std::any::Any;
|
||||||
mod macros;
|
|
||||||
pub mod address;
|
|
||||||
pub mod message;
|
|
||||||
pub mod actor;
|
|
||||||
|
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
||||||
pub use address::Address;
|
|
||||||
pub use address::BoxedAddress;
|
|
||||||
pub use address::InternalMessageHandler;
|
|
||||||
pub use anyhow;
|
pub use anyhow;
|
||||||
pub use message::InternalMessage;
|
|
||||||
pub use message::Message;
|
pub trait Message: Send + Any {
|
||||||
pub use message::MessageBundle;
|
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 {
|
||||||
|
value: Box<dyn std::any::Any>,
|
||||||
|
name: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InternalMessage {
|
||||||
|
pub fn new<M: Any>(message: M) -> InternalMessage {
|
||||||
|
InternalMessage {
|
||||||
|
value: Box::new(message),
|
||||||
|
name: std::any::type_name::<M>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_inner<M: Any>(self) -> Result<M, InternalMessage> {
|
||||||
|
self.value
|
||||||
|
.downcast()
|
||||||
|
.map(|v| *v)
|
||||||
|
.map_err(|value| InternalMessage {
|
||||||
|
value,
|
||||||
|
name: self.name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ref<M: Any>(&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<MB> {
|
||||||
|
fn send<M: Message>(&mut self, message: M) -> impl Future<Output = anyhow::Result<M::Reply>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InternalMessageHandler {
|
||||||
|
type HandledMessages: MessageBundle;
|
||||||
|
fn handle_message(
|
||||||
|
&mut self,
|
||||||
|
msg: InternalMessage,
|
||||||
|
) -> impl Future<Output = anyhow::Result<InternalMessage>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<IMH> Address<IMH::HandledMessages> for IMH
|
||||||
|
where
|
||||||
|
IMH: InternalMessageHandler,
|
||||||
|
{
|
||||||
|
fn send<M: Message>(&mut self, message: M) -> impl Future<Output = anyhow::Result<M::Reply>> {
|
||||||
|
const {
|
||||||
|
let true = <M as IsContainedInBundle<IMH::HandledMessages>>::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::<M::Reply>().map_err(|e| {
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"Expected a {}, but got a {}",
|
||||||
|
std::any::type_name::<M::Reply>(),
|
||||||
|
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<M: Message> MessageBundle for (M,) {
|
||||||
|
const IDS: BundleChain = BundleChain::of::<M>();
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct BundleChain {
|
pub struct BundleChain {
|
||||||
|
|
@ -24,21 +117,13 @@ pub struct BundleChain {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum BundleOp {
|
pub enum BundleOp {
|
||||||
Add(TypeId),
|
Add(TypeId),
|
||||||
Remove(TypeId),
|
Remove(TypeId),
|
||||||
Chain(&'static BundleChain),
|
Chain(&'static BundleChain),
|
||||||
None,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BundleChain {
|
impl BundleChain {
|
||||||
pub const fn empty() -> BundleChain {
|
|
||||||
BundleChain {
|
|
||||||
op: BundleOp::None,
|
|
||||||
next: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn of<M: Message>() -> BundleChain {
|
pub const fn of<M: Message>() -> BundleChain {
|
||||||
BundleChain {
|
BundleChain {
|
||||||
op: BundleOp::Add(TypeId::of::<M>()),
|
op: BundleOp::Add(TypeId::of::<M>()),
|
||||||
|
|
@ -50,40 +135,6 @@ impl BundleChain {
|
||||||
check_is_contained(self, id)
|
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<M: Message>(&'static self) -> BundleChain {
|
pub const fn with<M: Message>(&'static self) -> BundleChain {
|
||||||
let to_add = TypeId::of::<M>();
|
let to_add = TypeId::of::<M>();
|
||||||
BundleChain {
|
BundleChain {
|
||||||
|
|
@ -108,6 +159,24 @@ impl BundleChain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
pub trait IsContainedInBundle<MB> {
|
||||||
const IS_CONTAINED: bool;
|
const IS_CONTAINED: bool;
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +186,7 @@ where
|
||||||
M: Message,
|
M: Message,
|
||||||
MB: MessageBundle,
|
MB: MessageBundle,
|
||||||
{
|
{
|
||||||
const IS_CONTAINED: bool = check_is_contained(&MB::CHAIN, TypeId::of::<M>());
|
const IS_CONTAINED: bool = check_is_contained(&MB::IDS, TypeId::of::<M>());
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn check_is_contained(ids: &BundleChain, id: TypeId) -> bool {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BundleOp::None => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(next) = ids.next {
|
if let Some(next) = ids.next {
|
||||||
|
|
@ -201,16 +269,6 @@ mod tests {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn check_subset() {
|
|
||||||
const CHAIN: BundleChain = BundleChain::of::<Foo>().join(&BundleChain::of::<Bar>());
|
|
||||||
const SUB: BundleChain = BundleChain::of::<Foo>().with::<Bar>();
|
|
||||||
|
|
||||||
assert!(SUB.is_subset_of(&CHAIN));
|
|
||||||
|
|
||||||
assert!(!BundleChain::of::<Zap>().is_subset_of(&CHAIN));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[apply(test!)]
|
#[apply(test!)]
|
||||||
async fn check_sending_messages() {
|
async fn check_sending_messages() {
|
||||||
struct Sender;
|
struct Sender;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -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<dyn std::any::Any>,
|
|
||||||
name: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InternalMessage {
|
|
||||||
pub fn new<M: Any>(message: M) -> InternalMessage {
|
|
||||||
InternalMessage {
|
|
||||||
value: Box::new(message),
|
|
||||||
name: std::any::type_name::<M>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_inner<M: Any>(self) -> Result<M, InternalMessage> {
|
|
||||||
self.value
|
|
||||||
.downcast()
|
|
||||||
.map(|v| *v)
|
|
||||||
.map_err(|value| InternalMessage {
|
|
||||||
value,
|
|
||||||
name: self.name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ref<M: Any>(&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);
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use tytix_core::BoxedAddress;
|
|
||||||
use tytix_core::InternalMessage;
|
use tytix_core::InternalMessage;
|
||||||
use tytix_core::InternalMessageHandler;
|
use tytix_core::InternalMessageHandler;
|
||||||
use tytix_core::IsContainedInBundle;
|
use tytix_core::IsContainedInBundle;
|
||||||
|
|
@ -19,29 +18,17 @@ pub trait AddressExt<MB> {
|
||||||
|
|
||||||
fn inspect<F, M, U>(self, f: F) -> Inspect<Self, F, U, M>
|
fn inspect<F, M, U>(self, f: F) -> Inspect<Self, F, U, M>
|
||||||
where
|
where
|
||||||
Inspect<Self, F, U, M>: InternalMessageHandler,
|
F: Fn(&M) -> U,
|
||||||
|
M: Message + IsContainedInBundle<MB>,
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
fn join<Other>(self, o: Other) -> Joined<Self, Other>
|
fn join<Other>(self, o: Other) -> Joined<Self, Other>
|
||||||
where
|
where
|
||||||
Joined<Self, Other>: InternalMessageHandler,
|
Joined<Self, Other>: InternalMessageHandler,
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
fn simplify<SMB>(self) -> SimpleAddress<SMB, Self>
|
|
||||||
where
|
|
||||||
SimpleAddress<SMB, Self>: InternalMessageHandler,
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
fn boxed(self) -> BoxedAddress<MB>
|
|
||||||
where
|
|
||||||
BoxedAddress<MB>: InternalMessageHandler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MB, A> AddressExt<MB> for A
|
impl<MB: MessageBundle, A: InternalMessageHandler<HandledMessages = MB>> AddressExt<MB> for A {
|
||||||
where
|
|
||||||
MB: MessageBundle,
|
|
||||||
A: InternalMessageHandler<HandledMessages = MB> + 'static,
|
|
||||||
{
|
|
||||||
fn map<M, F, U, RF, RU>(self, f: F, r: RF) -> MappedMessage<Self, M, F, U, RF, RU>
|
fn map<M, F, U, RF, RU>(self, f: F, r: RF) -> MappedMessage<Self, M, F, U, RF, RU>
|
||||||
where
|
where
|
||||||
MappedMessage<Self, M, F, U, RF, RU>: InternalMessageHandler,
|
MappedMessage<Self, M, F, U, RF, RU>: InternalMessageHandler,
|
||||||
|
|
@ -57,9 +44,16 @@ where
|
||||||
|
|
||||||
fn inspect<F, M, U>(self, f: F) -> Inspect<Self, F, U, M>
|
fn inspect<F, M, U>(self, f: F) -> Inspect<Self, F, U, M>
|
||||||
where
|
where
|
||||||
Inspect<Self, F, U, M>: InternalMessageHandler,
|
F: Fn(&M) -> U,
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
M: Message + IsContainedInBundle<MB>,
|
||||||
{
|
{
|
||||||
|
const {
|
||||||
|
let true = <M as IsContainedInBundle<MB>>::IS_CONTAINED else {
|
||||||
|
panic!("Message is not contained in MessageBundle",);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Inspect {
|
Inspect {
|
||||||
address: self,
|
address: self,
|
||||||
func: f,
|
func: f,
|
||||||
|
|
@ -77,47 +71,6 @@ where
|
||||||
right: o,
|
right: o,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simplify<SMB>(self) -> SimpleAddress<SMB, Self>
|
|
||||||
where
|
|
||||||
SimpleAddress<SMB, Self>: InternalMessageHandler,
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
SimpleAddress {
|
|
||||||
inner: self,
|
|
||||||
_pd: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn boxed(self) -> BoxedAddress<MB> {
|
|
||||||
BoxedAddress::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SimpleAddress<MB, A> {
|
|
||||||
inner: A,
|
|
||||||
_pd: PhantomData<fn(MB)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<SMB, MB, A> InternalMessageHandler for SimpleAddress<SMB, A>
|
|
||||||
where
|
|
||||||
SMB: MessageBundle,
|
|
||||||
MB: MessageBundle,
|
|
||||||
A: InternalMessageHandler<HandledMessages = MB>,
|
|
||||||
{
|
|
||||||
type HandledMessages = SMB;
|
|
||||||
|
|
||||||
fn handle_message(
|
|
||||||
&mut self,
|
|
||||||
msg: InternalMessage,
|
|
||||||
) -> impl Future<Output = anyhow::Result<InternalMessage>> {
|
|
||||||
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<L, R> {
|
pub struct Joined<L, R> {
|
||||||
|
|
@ -134,8 +87,7 @@ where
|
||||||
L: MessageBundle,
|
L: MessageBundle,
|
||||||
R: MessageBundle,
|
R: MessageBundle,
|
||||||
{
|
{
|
||||||
const CHAIN: tytix_core::BundleChain =
|
const IDS: tytix_core::BundleChain = <L as MessageBundle>::IDS.join(&<R as MessageBundle>::IDS);
|
||||||
<L as MessageBundle>::CHAIN.join(&<R as MessageBundle>::CHAIN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L, R> InternalMessageHandler for Joined<L, R>
|
impl<L, R> InternalMessageHandler for Joined<L, R>
|
||||||
|
|
@ -148,7 +100,7 @@ where
|
||||||
async fn handle_message(&mut self, msg: InternalMessage) -> anyhow::Result<InternalMessage> {
|
async fn handle_message(&mut self, msg: InternalMessage) -> anyhow::Result<InternalMessage> {
|
||||||
let message_id = msg.type_id();
|
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
|
self.left.handle_message(msg).await
|
||||||
} else {
|
} else {
|
||||||
self.right.handle_message(msg).await
|
self.right.handle_message(msg).await
|
||||||
|
|
@ -196,7 +148,7 @@ where
|
||||||
M: Message,
|
M: Message,
|
||||||
R: Message + IsContainedInBundle<MB>,
|
R: Message + IsContainedInBundle<MB>,
|
||||||
{
|
{
|
||||||
const CHAIN: tytix_core::BundleChain = MB::CHAIN.without::<R>().with::<M>();
|
const IDS: tytix_core::BundleChain = MB::IDS.without::<R>().with::<M>();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, M, R, F, U, RF, RU> InternalMessageHandler for MappedMessage<A, M, F, U, RF, RU>
|
impl<A, M, R, F, U, RF, RU> InternalMessageHandler for MappedMessage<A, M, F, U, RF, RU>
|
||||||
|
|
@ -267,9 +219,9 @@ mod tests {
|
||||||
type Reply = usize;
|
type Reply = usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FooBarAddress;
|
struct SimpleAddress;
|
||||||
|
|
||||||
impl InternalMessageHandler for FooBarAddress {
|
impl InternalMessageHandler for SimpleAddress {
|
||||||
type HandledMessages = (Foo, Bar);
|
type HandledMessages = (Foo, Bar);
|
||||||
|
|
||||||
async fn handle_message(
|
async fn handle_message(
|
||||||
|
|
@ -301,7 +253,7 @@ mod tests {
|
||||||
async fn check_mapping() {
|
async fn check_mapping() {
|
||||||
static MSG: OnceLock<bool> = OnceLock::new();
|
static MSG: OnceLock<bool> = OnceLock::new();
|
||||||
|
|
||||||
let mut sa = FooBarAddress.map(
|
let mut sa = SimpleAddress.map(
|
||||||
|_b: Bar| {
|
|_b: Bar| {
|
||||||
let _ = MSG.set(true);
|
let _ = MSG.set(true);
|
||||||
async { Foo }
|
async { Foo }
|
||||||
|
|
@ -318,7 +270,7 @@ mod tests {
|
||||||
async fn check_inspect() {
|
async fn check_inspect() {
|
||||||
static MSG: OnceLock<bool> = OnceLock::new();
|
static MSG: OnceLock<bool> = OnceLock::new();
|
||||||
|
|
||||||
let mut sa = FooBarAddress.inspect(|_b: &Bar| {
|
let mut sa = SimpleAddress.inspect(|_b: &Bar| {
|
||||||
let _ = MSG.set(true);
|
let _ = MSG.set(true);
|
||||||
async {}
|
async {}
|
||||||
});
|
});
|
||||||
|
|
@ -333,11 +285,11 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[apply(test!)]
|
#[apply(test!)]
|
||||||
async fn check_simplify() {
|
async fn check_join() {
|
||||||
static MSG_SA: OnceLock<bool> = OnceLock::new();
|
static MSG_SA: OnceLock<bool> = OnceLock::new();
|
||||||
static MSG_ZAP: OnceLock<bool> = OnceLock::new();
|
static MSG_ZAP: OnceLock<bool> = OnceLock::new();
|
||||||
|
|
||||||
let sa = FooBarAddress.inspect(|_b: &Bar| {
|
let sa = SimpleAddress.inspect(|_b: &Bar| {
|
||||||
MSG_SA.set(true).unwrap();
|
MSG_SA.set(true).unwrap();
|
||||||
async {}
|
async {}
|
||||||
});
|
});
|
||||||
|
|
@ -356,42 +308,4 @@ mod tests {
|
||||||
|
|
||||||
MSG_ZAP.get().expect("The message was NOT inspected!");
|
MSG_ZAP.get().expect("The message was NOT inspected!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[apply(test!)]
|
|
||||||
async fn check_join() {
|
|
||||||
static MSG_SA: OnceLock<bool> = 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<bool> = 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!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue