Skip to main content

elfo_core/routers/
mod.rs

1use std::{
2    fmt::{self, Display},
3    hash::Hash,
4};
5
6use crate::{envelope::Envelope, msg};
7
8pub use self::map::MapRouter;
9
10mod map;
11
12pub trait Router<C>: Send + Sync + 'static {
13    type Key: Clone + Hash + Eq + Display + Send + Sync; // TODO: why is `Sync` required?
14
15    fn update(&self, _config: &C) {}
16    fn route(&self, envelope: &Envelope) -> Outcome<Self::Key>;
17}
18
19/// Specifies which actors will get a message.
20#[derive(Debug)]
21#[non_exhaustive]
22pub enum Outcome<T> {
23    /// Routes a message to an actor with the specified key.
24    /// If there is no active or restarting actor for this key,
25    /// it will be started.
26    Unicast(T),
27    /// Routes a message to an actor with the specified key.
28    /// If there is no active or restarting actor for this key,
29    /// the message will be discarded, no actors are started.
30    GentleUnicast(T),
31    /// Routes a message to all actors with specified keys.
32    /// If there is no active or restarting actors for these keys,
33    /// they will be started.
34    Multicast(Vec<T>),
35    /// Routes a message to all actors with specified keys.
36    /// If there is no active or restarting actors for these keys,
37    /// the message will be descarded, no actors are started.
38    GentleMulticast(Vec<T>),
39    /// Routes a message to all active actors.
40    Broadcast,
41    /// Discards a message.
42    /// If a message is discarded by everyone, the sending side gets an error.
43    Discard,
44    /// Route message using default behaviour.
45    /// This behaviour depends on the message type:
46    /// - `ValidateConfig` is routed as `Discard`
47    /// - All other system messages are routed as `Broadcast`
48    /// - All non-system messages are routed as `Discard`
49    Default,
50}
51
52assert_eq_size!(Outcome<u64>, [u8; 32]);
53assert_eq_size!(Outcome<u128>, [u8; 32]);
54
55impl<T> Outcome<T> {
56    /// Transforms `Unicast` and `Multicast` variants.
57    #[inline]
58    pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Outcome<U> {
59        match self {
60            Outcome::Unicast(val) => Outcome::Unicast(f(val)),
61            Outcome::GentleUnicast(val) => Outcome::GentleUnicast(f(val)),
62            Outcome::Multicast(list) => Outcome::Multicast(list.into_iter().map(f).collect()),
63            Outcome::GentleMulticast(list) => {
64                Outcome::GentleMulticast(list.into_iter().map(f).collect())
65            }
66            Outcome::Broadcast => Outcome::Broadcast,
67            Outcome::Discard => Outcome::Discard,
68            Outcome::Default => Outcome::Default,
69        }
70    }
71
72    /// Replaces the `Default` variant with the provided one.
73    #[inline]
74    pub fn or(self, outcome: Outcome<T>) -> Self {
75        match self {
76            Outcome::Default => outcome,
77            _ => self,
78        }
79    }
80}
81
82impl<C> Router<C> for () {
83    type Key = Singleton;
84
85    #[inline]
86    fn route(&self, envelope: &Envelope) -> Outcome<Self::Key> {
87        use crate::messages::*;
88
89        msg!(match envelope {
90            // These messages shouldn't spawn actors.
91            // TODO: maybe this logic should be in the supervisor.
92            Terminate | Ping => Outcome::GentleUnicast(Singleton),
93            ValidateConfig => Outcome::Default,
94            _ => Outcome::Unicast(Singleton),
95        })
96    }
97}
98
99/// A key used for actor groups containing only one actor.
100#[derive(Debug, Clone, Hash, PartialEq, Eq)]
101pub struct Singleton;
102
103impl fmt::Display for Singleton {
104    #[inline]
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        // If this line is changed, change also a key in `start.rs` to be consistent.
107        f.write_str("_")
108    }
109}