Skip to main content

polybox_core/
interface.rs

1use super::*;
2use std::any::TypeId;
3use type_sets::Members;
4
5/// An interface defines the set of messages that can be sent to a given actor.
6/// This is usually derived on an enum using the `#[derive(Interface)]` macro.
7///
8/// It defines conversion methods to and from a boxed payload, which is used for dynamic dispatch of messages.
9pub trait Interface:
10    Message<Kind = FireAndForget>
11    + TryIntoPayload<Self>
12    + FromPayload<Self>
13    + AsSet
14    + Sized
15    + Send
16    + 'static
17{
18    fn try_from_boxed_payload(payload: BoxedPayload) -> Result<Self, BoxedPayload>;
19    fn into_boxed_payload(self) -> BoxedPayload;
20
21    fn try_from_any_payload<I: Message>(payload: Payload<I>) -> Result<Self, Payload<I>>
22    where
23        Payload<I>: Send,
24    {
25        // This can be implemented faster using unsafe transmute
26        Self::try_from_boxed_payload(BoxedPayload::new::<I>(payload))
27            .map_err(|payload| payload.downcast::<I>().expect("Conversion back"))
28    }
29
30    fn try_into_any_payload<I: Message>(self) -> Result<Payload<I>, Self> {
31        // This can be implemented faster using unsafe transmute
32        self.into_boxed_payload()
33            .downcast::<I>()
34            .map_err(|payload| Self::try_from_boxed_payload(payload).expect("Conversion back"))
35    }
36
37    fn invocable_with(type_id: TypeId) -> bool {
38        Self::members().contains(&type_id)
39    }
40}
41
42pub trait FromPayload<T: Message> {
43    fn from_payload(payload: Payload<T>) -> Self;
44}
45
46pub trait TryIntoPayload<T: Message>: Sized {
47    fn try_into_payload(self) -> Result<Payload<T>, Self>;
48}