Skip to main content

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}