use std::any::Any;
use std::fmt::{self, Debug};
use std::pin::Pin;
use crate::actor::Actor;
use crate::channel::oneshot;
use crate::message::{Handler, Message};
mod default_proxy;
pub use default_proxy::DefaultEnvelopeProxy;
pub trait ToEnvelope<A, M, EP = DefaultEnvelopeProxy<M>>
where
A: Actor + Handler<M>,
M: Message,
{
fn pack(msg: M, tx: Option<oneshot::Sender<M::Result>>) -> Envelope<A>;
}
pub trait FromEnvelope<A, M, EP = DefaultEnvelopeProxy<M>>
where
A: Actor + Handler<M>,
M: Message,
{
fn unpack(envelope: Envelope<A>) -> M;
}
pub trait EnvelopeProxy<A>: Send
where
A: Actor,
{
fn handle<'a, 'b>(
&'a mut self,
actor: &'b mut A,
ctx: &'b mut A::Context,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>
where
'b: 'a;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
#[repr(transparent)]
pub struct Envelope<A>(Box<dyn EnvelopeProxy<A> + Send>)
where
A: Actor;
impl<A> Debug for Envelope<A>
where
A: Actor,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("Envelope<{}>", crate::utils::type_name::<A>()))
}
}
impl<A> Envelope<A>
where
A: Actor,
{
pub fn with_proxy(proxy: Box<dyn EnvelopeProxy<A> + Send>) -> Self {
Self(proxy)
}
}
impl<A> EnvelopeProxy<A> for Envelope<A>
where
A: Actor,
{
fn handle<'a, 'b>(
&'a mut self,
actor: &'b mut A,
ctx: &'b mut A::Context,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>
where
'b: 'a,
{
self.0.handle(actor, ctx)
}
fn as_any(&self) -> &dyn Any {
self.0.as_any()
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self.0.as_any_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::{Dummy, Ping};
#[test]
fn test_envelope() {
let default_proxy = DefaultEnvelopeProxy {
message: Some(Ping(42)),
tx: None,
};
let debug_str = format!("{default_proxy:?}");
assert_eq!(debug_str, "DefaultEnvelopeProxy<Ping>");
let envelope = Envelope::<Dummy>::with_proxy(Box::new(default_proxy));
let debug_str = format!("{envelope:?}");
assert_eq!(debug_str, "Envelope<Dummy>");
let trait_object = envelope.as_any();
assert!(trait_object.is::<DefaultEnvelopeProxy<Ping>>());
}
}