Skip to main content

elfo_core/
messages.rs

1use std::{fmt::Display, sync::Arc};
2
3use derive_more::Constructor;
4
5use crate::{
6    actor::ActorMeta, actor_status::ActorStatus, config::AnyConfig, message, signal::SignalKind,
7};
8
9/// A helper type for using in generic code (e.g. as an associated type) to
10/// indicate a message that cannot be constructed.
11///
12/// Feel free to define a custom `Impossible` type as an empty enum if more
13/// implemented traits are needed.
14#[message]
15#[derive(Eq, PartialEq, Hash, Copy)]
16pub enum Impossible {}
17
18/// Checks that the actor is able to handle messages.
19/// Routed to all actors in a group by default and handled implicitly by actors.
20#[message(ret = ())]
21#[derive(Default)]
22#[non_exhaustive]
23pub struct Ping;
24
25#[message(ret = Result<(), ConfigRejected>)]
26#[derive(Constructor)]
27#[non_exhaustive]
28pub struct ValidateConfig {
29    pub config: AnyConfig,
30}
31
32#[message(ret = Result<(), ConfigRejected>)]
33#[derive(Constructor)]
34#[non_exhaustive]
35pub struct UpdateConfig {
36    pub config: AnyConfig,
37}
38
39#[message]
40#[non_exhaustive]
41pub struct ConfigRejected {
42    pub reason: String,
43}
44
45impl<R: Display> From<R> for ConfigRejected {
46    fn from(reason: R) -> Self {
47        Self {
48            reason: reason.to_string(),
49        }
50    }
51}
52
53#[message(ret = Result<(), StartEntrypointRejected>)]
54#[derive(Constructor)]
55#[non_exhaustive]
56pub struct StartEntrypoint {
57    pub is_check_only: bool,
58}
59
60#[message(part)]
61#[derive(Constructor)]
62#[non_exhaustive]
63pub struct StartEntrypointRejected {
64    pub errors: Vec<EntrypointError>,
65}
66
67#[message(part)]
68#[derive(Constructor)]
69#[non_exhaustive]
70pub struct EntrypointError {
71    pub group: String,
72    pub reason: String,
73}
74
75#[message]
76#[non_exhaustive]
77pub struct ConfigUpdated {
78    // TODO: add `old_config`.
79}
80
81#[message]
82#[derive(Default)]
83#[non_exhaustive]
84pub struct Terminate {
85    pub(crate) closing: bool,
86    #[serde(default)]
87    pub reason: TerminateReason,
88}
89
90impl Terminate {
91    /// The message closes a target's mailbox ignoring `TerminationPolicy`.
92    pub fn closing() -> Self {
93        Self {
94            closing: true,
95            reason: TerminateReason::Unknown,
96        }
97    }
98
99    /// Create terminate message with provided reason
100    pub fn with_reason(mut self, reason: TerminateReason) -> Self {
101        self.reason = reason;
102        self
103    }
104}
105
106#[message(part)]
107#[derive(Default, PartialEq)]
108#[non_exhaustive]
109pub enum TerminateReason {
110    #[default]
111    Unknown,
112    Signal(SignalKind),
113    Oom,
114    Custom(Arc<str>),
115}
116
117impl TerminateReason {
118    pub fn custom(reason: impl Into<Arc<str>>) -> Self {
119        Self::Custom(reason.into())
120    }
121}
122
123// === Status ===
124
125// TODO: should it be a request?
126#[message]
127#[derive(Default)]
128#[non_exhaustive]
129pub struct SubscribeToActorStatuses {
130    pub(crate) forcing: bool,
131}
132
133impl SubscribeToActorStatuses {
134    /// Statuses will be sent even if a subscriber is already registered.
135    pub fn forcing() -> Self {
136        Self { forcing: true }
137    }
138}
139
140#[message]
141#[non_exhaustive]
142pub struct ActorStatusReport {
143    pub meta: Arc<ActorMeta>,
144    pub status: ActorStatus,
145}
146
147impl ActorStatusReport {
148    #[cfg(feature = "test-util")]
149    pub fn new(meta: impl Into<Arc<ActorMeta>>, status: ActorStatus) -> Self {
150        Self {
151            meta: meta.into(),
152            status,
153        }
154    }
155}