Make everything async

Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
Marcel Müller 2025-11-04 09:42:03 +01:00
parent 9ff1cf1bac
commit f3f816acd9
5 changed files with 497 additions and 36 deletions

View file

@ -4,6 +4,8 @@
use std::any::Any;
use std::any::TypeId;
pub use anyhow;
pub trait Message: Send + Any {
type Reply: Send + Any;
}
@ -16,28 +18,44 @@ impl<M: Message> MessageIdentifier for M {
const IDENT: BundleChain = BundleChain::of::<M>();
}
pub struct InternalMessage(Box<dyn std::any::Any>);
pub struct InternalMessage {
value: Box<dyn std::any::Any>,
name: &'static str,
}
impl InternalMessage {
pub fn new(message: impl Message) -> InternalMessage {
InternalMessage(Box::new(message))
pub fn new<M: Any>(message: M) -> InternalMessage {
InternalMessage {
value: Box::new(message),
name: std::any::type_name::<M>(),
}
}
pub fn into_inner<M: Message>(self) -> Result<M, InternalMessage> {
self.0.downcast().map(|v| *v).map_err(InternalMessage)
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 type_name(&self) -> &'static str {
self.name
}
}
pub trait Address<MB>
where
MB: MessageBundle,
{
fn send<M: Message>(&mut self, message: M);
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);
fn handle_message(
&mut self,
msg: InternalMessage,
) -> impl Future<Output = anyhow::Result<InternalMessage>>;
}
impl<MB, IMH> Address<MB> for IMH
@ -45,14 +63,26 @@ where
MB: MessageBundle,
IMH: InternalMessageHandler<HandledMessages = MB>,
{
fn send<M: Message>(&mut self, message: M) {
fn send<M: Message>(&mut self, message: M) -> impl Future<Output = anyhow::Result<M::Reply>> {
const {
let true = <M as IsContainedInBundle<MB>>::IS_CONTAINED else {
panic!("Message is not contained in MessageBundle",);
};
}
self.handle_message(InternalMessage(Box::new(message)));
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()
)
})
})
}
}
}
@ -173,6 +203,9 @@ const fn remove_from_chain(prev: &'static BundleChain, to_remove: TypeId) -> Bun
#[cfg(test)]
mod tests {
use macro_rules_attribute::apply;
use smol_macros::test;
use super::*;
struct Foo;
@ -218,18 +251,23 @@ mod tests {
));
}
#[test]
fn check_sending_messages() {
#[apply(test!)]
async fn check_sending_messages() {
struct Sender;
impl InternalMessageHandler for Sender {
type HandledMessages = (Foo, Bar);
fn handle_message(&mut self, _msg: InternalMessage) {}
async fn handle_message(
&mut self,
_msg: InternalMessage,
) -> anyhow::Result<InternalMessage> {
Err(anyhow::anyhow!("Not implemented!"))
}
}
let mut s = Sender;
s.send(Foo);
s.send(Foo).await.unwrap_err();
}
}