behavior_actors/atomic/fixed_supervisor/protocol.rs
1//! FixedSupervisor commands and read-only replies.
2
3use behavior::{Address, EndpointAddress, EstablishedRecipient, MessageProtocol, Protocol};
4
5use crate::ReplyRoute;
6
7/// Read-only phase of one fixed roster member.
8pub enum MemberStatus<Service>
9where
10 Service: Protocol,
11 Service::Addr: EndpointAddress,
12{
13 /// The stable proxy is not committed yet.
14 CreatingProxy,
15 /// The proxy is waiting for global activation capacity.
16 WaitingForActivation,
17 /// Initial or replacement input is awaiting its atomic proxy outcome.
18 AwaitingProxy,
19 /// The stable proxy is ready to accept service messages.
20 Ready {
21 /// Exact capability of the ready stable proxy, never its worker.
22 proxy: EstablishedRecipient<Service>,
23 },
24 /// The stable proxy has no current worker.
25 Empty,
26 /// The role belongs to one coordinated recovery.
27 Recovering,
28 /// The stable proxy is retiring.
29 Stopping,
30 /// The role no longer owns a stable proxy.
31 Retired,
32}
33
34/// Fixed roster status in the original declaration order.
35pub struct FixedSnapshot<Service>
36where
37 Service: Protocol,
38 Service::Addr: EndpointAddress,
39{
40 /// One status per declared role, in semantic roster order.
41 pub members: Vec<MemberStatus<Service>>,
42}
43
44/// Non-ready phase returned by an exact capability query.
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
46pub enum UnavailablePhase {
47 /// The stable proxy is not committed yet.
48 CreatingProxy,
49 /// The proxy is waiting for global activation capacity.
50 WaitingForActivation,
51 /// Initial or replacement input is awaiting its atomic proxy outcome.
52 AwaitingProxy,
53 /// The stable proxy has no current worker.
54 Empty,
55 /// The role belongs to one coordinated recovery.
56 Recovering,
57 /// The stable proxy is retiring.
58 Stopping,
59 /// The role no longer owns a stable proxy.
60 Retired,
61}
62
63impl UnavailablePhase {
64 pub(super) fn status<Service>(self) -> MemberStatus<Service>
65 where
66 Service: Protocol,
67 Service::Addr: EndpointAddress,
68 {
69 match self {
70 Self::CreatingProxy => MemberStatus::CreatingProxy,
71 Self::WaitingForActivation => MemberStatus::WaitingForActivation,
72 Self::AwaitingProxy => MemberStatus::AwaitingProxy,
73 Self::Empty => MemberStatus::Empty,
74 Self::Recovering => MemberStatus::Recovering,
75 Self::Stopping => MemberStatus::Stopping,
76 Self::Retired => MemberStatus::Retired,
77 }
78 }
79}
80
81/// Result of querying one submitted semantic role.
82pub enum CapabilityResult<Role, Service>
83where
84 Service: Protocol,
85 Service::Addr: EndpointAddress,
86{
87 /// The role is ready through its stable proxy.
88 Ready {
89 /// Exact submitted role value.
90 role: Role,
91 /// Exact stable proxy capability.
92 proxy: EstablishedRecipient<Service>,
93 },
94 /// The role exists but is not ready.
95 Unavailable {
96 /// Exact submitted role value.
97 role: Role,
98 /// Current non-ready phase.
99 phase: UnavailablePhase,
100 },
101 /// No declared role equals the submitted value.
102 UnknownRole {
103 /// Exact submitted role returned unchanged.
104 submitted: Role,
105 },
106}
107
108/// Management input accepted by one fixed supervisor.
109///
110/// A recipient for another reply protocol cannot be substituted:
111///
112/// ```compile_fail,E0277
113/// #[derive(Clone, Copy, Eq, PartialEq)]
114/// struct RuntimeAddress;
115/// impl behavior::Address for RuntimeAddress { type Nonce = u64; }
116/// #[derive(Clone)]
117/// struct Endpoint;
118/// struct Installed<B: behavior::Behavior>(Endpoint, std::sync::mpsc::Sender<B::Event>);
119/// impl<B: behavior::Behavior> Clone for Installed<B> {
120/// fn clone(&self) -> Self { Self(self.0.clone(), self.1.clone()) }
121/// }
122/// impl behavior::EndpointAddress for RuntimeAddress {
123/// type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
124/// type Installed<B> = Installed<B>
125/// where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>>;
126/// fn recipient<B>(installed: &Self::Installed<B>) -> Endpoint
127/// where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>> {
128/// installed.0.clone()
129/// }
130/// }
131/// struct Service;
132/// impl behavior::Protocol for Service {
133/// type Addr = RuntimeAddress;
134/// type Msg = u8;
135/// }
136/// let wrong = behavior::Recipient::<
137/// behavior::MessageProtocol<RuntimeAddress, u8>
138/// >::global(RuntimeAddress);
139/// let _: behavior_actors::atomic::FixedCommand<RuntimeAddress, u16, Service> =
140/// behavior_actors::atomic::FixedCommand::status(wrong);
141/// ```
142pub enum FixedCommand<A, Role, Service>
143where
144 A: Address + EndpointAddress,
145 Service: Protocol<Addr = A>,
146{
147 /// Query every member status in declaration order.
148 Status {
149 /// Temporary logical or exact status recipient.
150 reply_to: ReplyRoute<MessageProtocol<A, FixedSnapshot<Service>>>,
151 },
152 /// Query the stable service capability for one semantic role.
153 Capability {
154 /// Submitted role value, returned in every capability result.
155 role: Role,
156 /// Temporary logical or exact capability-result recipient.
157 reply_to: ReplyRoute<MessageProtocol<A, CapabilityResult<Role, Service>>>,
158 },
159 /// Close recovery admission and retire the complete owned actor graph.
160 Shutdown,
161}
162
163impl<A, Role, Service> FixedCommand<A, Role, Service>
164where
165 A: Address + EndpointAddress,
166 Service: Protocol<Addr = A>,
167{
168 /// Construct a declaration-ordered status query.
169 #[must_use]
170 pub fn status<Route>(reply_to: Route) -> Self
171 where
172 Route: Into<ReplyRoute<MessageProtocol<A, FixedSnapshot<Service>>>>,
173 {
174 Self::Status {
175 reply_to: reply_to.into(),
176 }
177 }
178
179 /// Construct one semantic-role capability query.
180 #[must_use]
181 pub fn capability<Route>(role: Role, reply_to: Route) -> Self
182 where
183 Route: Into<ReplyRoute<MessageProtocol<A, CapabilityResult<Role, Service>>>>,
184 {
185 Self::Capability {
186 role,
187 reply_to: reply_to.into(),
188 }
189 }
190
191 /// Construct shutdown without a reply placeholder.
192 #[must_use]
193 pub const fn shutdown() -> Self {
194 Self::Shutdown
195 }
196}