autumn_plugin_grpc/
lifecycle.rs1use std::fmt;
20use std::sync::atomic::{AtomicU8, Ordering};
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24#[non_exhaustive]
25pub enum Lifecycle {
26 Idle,
28 Serving,
30 Draining,
32 Stopped,
34 Failed,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40#[non_exhaustive]
41pub enum LifecycleEvent {
42 Bound,
44 StartFailed,
46 ShutdownRequested,
48 Drained,
50 ServerExited,
52}
53
54impl Lifecycle {
55 #[must_use]
57 pub const fn next(self, event: LifecycleEvent) -> Option<Self> {
58 use LifecycleEvent::{Bound, Drained, ServerExited, ShutdownRequested, StartFailed};
59 match (self, event) {
60 (Self::Idle, Bound) => Some(Self::Serving),
61 (Self::Serving, ShutdownRequested) => Some(Self::Draining),
62 (Self::Idle, StartFailed) | (Self::Serving, ServerExited) => Some(Self::Failed),
63 (Self::Idle, ShutdownRequested) | (Self::Draining, Drained | ServerExited) => {
64 Some(Self::Stopped)
65 }
66 _ => None,
67 }
68 }
69
70 #[must_use]
72 pub const fn is_ready(self) -> bool {
73 matches!(self, Self::Serving)
74 }
75
76 #[must_use]
78 pub const fn is_terminal(self) -> bool {
79 matches!(self, Self::Stopped | Self::Failed)
80 }
81
82 #[must_use]
84 pub const fn as_str(self) -> &'static str {
85 match self {
86 Self::Idle => "idle",
87 Self::Serving => "serving",
88 Self::Draining => "draining",
89 Self::Stopped => "stopped",
90 Self::Failed => "failed",
91 }
92 }
93
94 const fn to_u8(self) -> u8 {
95 match self {
96 Self::Idle => 0,
97 Self::Serving => 1,
98 Self::Draining => 2,
99 Self::Stopped => 3,
100 Self::Failed => 4,
101 }
102 }
103
104 const fn from_u8(value: u8) -> Self {
105 match value {
106 0 => Self::Idle,
107 1 => Self::Serving,
108 2 => Self::Draining,
109 3 => Self::Stopped,
110 _ => Self::Failed,
111 }
112 }
113}
114
115impl fmt::Display for Lifecycle {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 f.write_str(self.as_str())
118 }
119}
120
121#[derive(Debug)]
124pub struct LifecycleCell(AtomicU8);
125
126impl LifecycleCell {
127 #[must_use]
129 pub const fn new() -> Self {
130 Self(AtomicU8::new(Lifecycle::Idle.to_u8()))
131 }
132
133 #[must_use]
135 pub fn get(&self) -> Lifecycle {
136 Lifecycle::from_u8(self.0.load(Ordering::Acquire))
137 }
138
139 pub fn apply(&self, event: LifecycleEvent) -> Result<Lifecycle, Lifecycle> {
145 let mut current = self.0.load(Ordering::Acquire);
146 loop {
147 let state = Lifecycle::from_u8(current);
148 let next = state.next(event).ok_or(state)?;
149 match self.0.compare_exchange_weak(
150 current,
151 next.to_u8(),
152 Ordering::AcqRel,
153 Ordering::Acquire,
154 ) {
155 Ok(_) => return Ok(next),
156 Err(actual) => current = actual,
157 }
158 }
159 }
160}
161
162impl Default for LifecycleCell {
163 fn default() -> Self {
164 Self::new()
165 }
166}