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}