1use alloc::string::String;
11use alloc::vec::Vec;
12use core::fmt::Write;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum ComponentLayer {
17 Core,
18 Filesystem,
19 Device,
20 Observability,
21 Platform,
22}
23
24impl ComponentLayer {
25 pub const fn as_str(self) -> &'static str {
26 match self {
27 ComponentLayer::Core => "core",
28 ComponentLayer::Filesystem => "filesystem",
29 ComponentLayer::Device => "device",
30 ComponentLayer::Observability => "observability",
31 ComponentLayer::Platform => "platform",
32 }
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum ComponentStability {
39 Stable,
41 Experimental,
43 Internal,
45}
46
47impl ComponentStability {
48 pub const fn as_str(self) -> &'static str {
49 match self {
50 ComponentStability::Stable => "stable",
51 ComponentStability::Experimental => "experimental",
52 ComponentStability::Internal => "internal",
53 }
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct ComponentManifest {
60 pub id: &'static str,
61 pub version: &'static str,
62 pub layer: ComponentLayer,
63 pub stability: ComponentStability,
64 pub description: &'static str,
65 pub capabilities: &'static [&'static str],
66 pub requires: &'static [&'static str],
67 pub provides: &'static [&'static str],
68}
69
70impl ComponentManifest {
71 pub const fn is_stable_public_interface(&self) -> bool {
72 matches!(self.stability, ComponentStability::Stable)
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub enum ComponentRegistryError {
79 MissingDependency {
80 component: &'static str,
81 dependency: &'static str,
82 },
83}
84
85#[derive(Debug)]
87pub struct ComponentRegistry {
88 components: &'static [ComponentManifest],
89}
90
91impl ComponentRegistry {
92 pub const fn new(components: &'static [ComponentManifest]) -> Self {
93 Self { components }
94 }
95
96 pub const fn components(&self) -> &'static [ComponentManifest] {
97 self.components
98 }
99
100 pub const fn len(&self) -> usize {
101 self.components.len()
102 }
103
104 pub const fn is_empty(&self) -> bool {
105 self.components.is_empty()
106 }
107
108 pub fn find(&self, id: &str) -> Option<&'static ComponentManifest> {
109 self.components.iter().find(|component| component.id == id)
110 }
111
112 pub fn validate_dependencies(&self) -> Result<(), ComponentRegistryError> {
113 for component in self.components.iter() {
114 for dependency in component.requires.iter() {
115 if self.find(dependency).is_none() {
116 return Err(ComponentRegistryError::MissingDependency {
117 component: component.id,
118 dependency,
119 });
120 }
121 }
122 }
123 Ok(())
124 }
125
126 pub fn render_sysfs_listing(&self) -> Vec<u8> {
128 let mut out = String::from("id version layer stability capabilities requires provides\n");
129 for component in self.components.iter() {
130 let _ = write!(
131 out,
132 "{} {} {} {} ",
133 component.id,
134 component.version,
135 component.layer.as_str(),
136 component.stability.as_str()
137 );
138 write_csv(&mut out, component.capabilities);
139 out.push(' ');
140 write_csv(&mut out, component.requires);
141 out.push(' ');
142 write_csv(&mut out, component.provides);
143 out.push('\n');
144 }
145 out.into_bytes()
146 }
147}
148
149fn write_csv(out: &mut String, values: &[&str]) {
150 if values.is_empty() {
151 out.push('-');
152 return;
153 }
154
155 for (idx, value) in values.iter().enumerate() {
156 if idx > 0 {
157 out.push(',');
158 }
159 out.push_str(value);
160 }
161}
162
163const VERSION: &str = env!("CARGO_PKG_VERSION");
164
165const BUILTIN_COMPONENTS: &[ComponentManifest] = &[
166 ComponentManifest {
167 id: "ahrightos-core",
168 version: VERSION,
169 layer: ComponentLayer::Core,
170 stability: ComponentStability::Stable,
171 description: "Kernel bootstrap, heap initialization, and base runtime contracts.",
172 capabilities: &["kernel.boot", "heap.init", "runtime.base"],
173 requires: &[],
174 provides: &["abi.ahrightos-core.v0"],
175 },
176 ComponentManifest {
177 id: "ahrightos-vfs",
178 version: VERSION,
179 layer: ComponentLayer::Filesystem,
180 stability: ComponentStability::Stable,
181 description: "Unified path resolution and mount dispatch for filesystem components.",
182 capabilities: &[
183 "vfs.mount-table",
184 "vfs.path-resolution",
185 "vfs.file-dispatch",
186 ],
187 requires: &["ahrightos-core"],
188 provides: &["api.vfs.v0"],
189 },
190 ComponentManifest {
191 id: "ahrightos-ramfs",
192 version: VERSION,
193 layer: ComponentLayer::Filesystem,
194 stability: ComponentStability::Stable,
195 description: "Volatile in-memory filesystem used for root paths and /run.",
196 capabilities: &["fs.ramfs", "fs.volatile-runtime"],
197 requires: &["ahrightos-vfs"],
198 provides: &["/run", "fs.ramfs.v0"],
199 },
200 ComponentManifest {
201 id: "ahrightos-blkfs",
202 version: VERSION,
203 layer: ComponentLayer::Filesystem,
204 stability: ComponentStability::Experimental,
205 description: "Block-backed filesystem for persistent teaching experiments.",
206 capabilities: &["fs.blkfs", "block-cache", "mount.blkfs"],
207 requires: &["ahrightos-vfs"],
208 provides: &["fs.blkfs.v0"],
209 },
210 ComponentManifest {
211 id: "ahrightos-procfs",
212 version: VERSION,
213 layer: ComponentLayer::Observability,
214 stability: ComponentStability::Experimental,
215 description: "Linux-inspired read-only process/system information pseudo filesystem.",
216 capabilities: &["proc.version", "proc.meminfo", "proc.mounts"],
217 requires: &["ahrightos-vfs"],
218 provides: &["/proc/version", "/proc/meminfo", "/proc/mounts"],
219 },
220 ComponentManifest {
221 id: "ahrightos-sysfs",
222 version: VERSION,
223 layer: ComponentLayer::Observability,
224 stability: ComponentStability::Experimental,
225 description: "Linux-inspired system attribute pseudo filesystem.",
226 capabilities: &["sys.kernel", "sys.component-inspection"],
227 requires: &["ahrightos-vfs"],
228 provides: &["/sys/kernel/name", "/sys/fs/ahrightos/components"],
229 },
230 ComponentManifest {
231 id: "ahrightos-devtmpfs",
232 version: VERSION,
233 layer: ComponentLayer::Device,
234 stability: ComponentStability::Experimental,
235 description: "Device-node entry point for built-in teaching character devices.",
236 capabilities: &["dev.null", "dev.zero"],
237 requires: &["ahrightos-vfs"],
238 provides: &["/dev/null", "/dev/zero"],
239 },
240 ComponentManifest {
241 id: "ahrightos-component-platform",
242 version: VERSION,
243 layer: ComponentLayer::Platform,
244 stability: ComponentStability::Experimental,
245 description: "Manifest and registry foundation for commercial extensions.",
246 capabilities: &[
247 "component.registry",
248 "component.manifest.v0",
249 "component.sysfs-export",
250 ],
251 requires: &["ahrightos-sysfs"],
252 provides: &["/sys/fs/ahrightos/components", "component.manifest.v0"],
253 },
254];
255
256static BUILTIN_COMPONENT_REGISTRY: ComponentRegistry = ComponentRegistry::new(BUILTIN_COMPONENTS);
257
258pub fn builtin_component_registry() -> &'static ComponentRegistry {
259 &BUILTIN_COMPONENT_REGISTRY
260}
261
262pub fn render_builtin_component_listing() -> Vec<u8> {
263 BUILTIN_COMPONENT_REGISTRY.render_sysfs_listing()
264}