serenade_kernel/
kernel.rs1use std::fmt::{Display, Formatter};
4
5use crate::{BundleInterface, BundleRegistry, Environment, KernelError};
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
9pub enum KernelPhase {
10 Created,
12 Compiled,
14 Booted,
16 Shutdown,
18}
19
20impl Display for KernelPhase {
21 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
22 f.write_str(match self {
23 Self::Created => "created",
24 Self::Compiled => "compiled",
25 Self::Booted => "booted",
26 Self::Shutdown => "shutdown",
27 })
28 }
29}
30
31pub struct Kernel {
45 environment: Environment,
46 debug: bool,
47 registry: BundleRegistry,
48 bundles: Vec<Box<dyn BundleInterface>>,
49 phase: KernelPhase,
50}
51
52impl Kernel {
53 #[must_use]
57 pub fn new(environment: Environment) -> Self {
58 let debug = environment.is_debug();
59 Self {
60 environment,
61 debug,
62 registry: BundleRegistry::new(),
63 bundles: Vec::new(),
64 phase: KernelPhase::Created,
65 }
66 }
67
68 #[must_use]
70 pub const fn with_debug(mut self, debug: bool) -> Self {
71 self.debug = debug;
72 self
73 }
74
75 #[must_use]
77 pub const fn environment(&self) -> &Environment {
78 &self.environment
79 }
80
81 #[must_use]
83 pub const fn debug(&self) -> bool {
84 self.debug
85 }
86
87 #[must_use]
89 pub const fn phase(&self) -> KernelPhase {
90 self.phase
91 }
92
93 #[must_use]
97 pub fn bundle_names(&self) -> Vec<&'static str> {
98 if self.phase == KernelPhase::Created {
99 self.registry.names()
100 } else {
101 self.bundles.iter().map(|bundle| bundle.name()).collect()
102 }
103 }
104
105 pub fn register_bundle(
112 &mut self,
113 bundle: impl BundleInterface + 'static,
114 ) -> Result<(), KernelError> {
115 self.ensure_phase("register", KernelPhase::Created)?;
116 self.registry.register(bundle)
117 }
118
119 pub fn compile(&mut self) -> Result<(), KernelError> {
126 self.ensure_phase("compile", KernelPhase::Created)?;
127 let registry = std::mem::take(&mut self.registry);
128 self.bundles = registry.sorted()?;
129 for bundle in &self.bundles {
130 bundle
131 .build()
132 .map_err(|error| wrap_bundle(bundle.name(), "build", error))?;
133 }
134 self.phase = KernelPhase::Compiled;
135 Ok(())
136 }
137
138 pub fn boot(&mut self) -> Result<(), KernelError> {
144 if self.phase == KernelPhase::Created {
145 self.compile()?;
146 }
147 self.ensure_phase("boot", KernelPhase::Compiled)?;
148 for bundle in &self.bundles {
149 bundle
150 .boot()
151 .map_err(|error| wrap_bundle(bundle.name(), "boot", error))?;
152 }
153 self.phase = KernelPhase::Booted;
154 Ok(())
155 }
156
157 pub fn shutdown(&mut self) -> Result<(), KernelError> {
163 self.ensure_phase("shutdown", KernelPhase::Booted)?;
164 for bundle in self.bundles.iter().rev() {
165 bundle
166 .shutdown()
167 .map_err(|error| wrap_bundle(bundle.name(), "shutdown", error))?;
168 }
169 self.phase = KernelPhase::Shutdown;
170 Ok(())
171 }
172
173 fn ensure_phase(&self, action: &'static str, expected: KernelPhase) -> Result<(), KernelError> {
174 if self.phase == expected {
175 Ok(())
176 } else {
177 Err(KernelError::InvalidState {
178 action,
179 state: self.phase,
180 })
181 }
182 }
183}
184
185impl std::fmt::Debug for Kernel {
186 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
187 f.debug_struct("Kernel")
188 .field("environment", &self.environment)
189 .field("debug", &self.debug)
190 .field("phase", &self.phase)
191 .field("bundles", &self.bundle_names())
192 .finish_non_exhaustive()
193 }
194}
195
196fn wrap_bundle(bundle: &'static str, phase: &'static str, error: KernelError) -> KernelError {
197 match error {
198 KernelError::Bundle { .. } => error,
199 other => KernelError::Bundle {
200 bundle,
201 phase,
202 message: other.to_string(),
203 },
204 }
205}