alp_core/wizard/models.rs
1// SPDX-License-Identifier: Apache-2.0
2//! Domain types for the project wizard and module scaffold.
3
4use std::fmt;
5
6// ---------------------------------------------------------------------------
7// Template IDs
8// ---------------------------------------------------------------------------
9
10/// Identifier of a project-wizard template, mapped 1:1 to its stable kebab-case slug.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum WizardTemplateId {
13 MinimalApp,
14 SensorStarter,
15 IotStarter,
16 EdgeAiStarter,
17 BoardDiagnostics,
18 HostToolingStarter,
19}
20
21impl WizardTemplateId {
22 /// Returns the stable kebab-case slug for this template id.
23 pub fn as_str(self) -> &'static str {
24 match self {
25 WizardTemplateId::MinimalApp => "minimal-app",
26 WizardTemplateId::SensorStarter => "sensor-starter",
27 WizardTemplateId::IotStarter => "iot-starter",
28 WizardTemplateId::EdgeAiStarter => "edge-ai-starter",
29 WizardTemplateId::BoardDiagnostics => "board-diagnostics",
30 WizardTemplateId::HostToolingStarter => "host-tooling-starter",
31 }
32 }
33
34 /// Parses a template slug back into a `WizardTemplateId`; `None` if unrecognized.
35 pub fn from_str(s: &str) -> Option<Self> {
36 match s {
37 "minimal-app" => Some(WizardTemplateId::MinimalApp),
38 "sensor-starter" => Some(WizardTemplateId::SensorStarter),
39 "iot-starter" => Some(WizardTemplateId::IotStarter),
40 "edge-ai-starter" => Some(WizardTemplateId::EdgeAiStarter),
41 "board-diagnostics" => Some(WizardTemplateId::BoardDiagnostics),
42 "host-tooling-starter" => Some(WizardTemplateId::HostToolingStarter),
43 _ => None,
44 }
45 }
46}
47
48impl fmt::Display for WizardTemplateId {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "{}", self.as_str())
51 }
52}
53
54/// Identifier of a module-scaffold template, mapped 1:1 to its stable kebab-case slug.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum ModuleTemplateId {
57 SensorDriver,
58 ConnectivityService,
59 InferenceStage,
60 DiagnosticsCheck,
61}
62
63impl ModuleTemplateId {
64 /// Returns the stable kebab-case slug for this module template id.
65 pub fn as_str(self) -> &'static str {
66 match self {
67 ModuleTemplateId::SensorDriver => "sensor-driver",
68 ModuleTemplateId::ConnectivityService => "connectivity-service",
69 ModuleTemplateId::InferenceStage => "inference-stage",
70 ModuleTemplateId::DiagnosticsCheck => "diagnostics-check",
71 }
72 }
73
74 /// Parses a module-template slug back into a `ModuleTemplateId`; `None` if unrecognized.
75 pub fn from_str(s: &str) -> Option<Self> {
76 match s {
77 "sensor-driver" => Some(ModuleTemplateId::SensorDriver),
78 "connectivity-service" => Some(ModuleTemplateId::ConnectivityService),
79 "inference-stage" => Some(ModuleTemplateId::InferenceStage),
80 "diagnostics-check" => Some(ModuleTemplateId::DiagnosticsCheck),
81 _ => None,
82 }
83 }
84}
85
86impl fmt::Display for ModuleTemplateId {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 write!(f, "{}", self.as_str())
89 }
90}
91
92// ---------------------------------------------------------------------------
93// Template definition building blocks
94// ---------------------------------------------------------------------------
95
96/// Connectivity/security feature toggles a template requests in its generated config.
97#[derive(Debug, Clone, Copy)]
98pub struct WizardFeatureFlags {
99 /// Enable Wi-Fi support.
100 pub wifi: bool,
101 /// Enable MQTT support.
102 pub mqtt: bool,
103 /// Enable Bluetooth Low Energy support.
104 pub ble: bool,
105 /// Enable TLS support.
106 pub tls: bool,
107}
108
109/// A single feature C file that a project template generates.
110pub struct FeatureFileSpec {
111 /// Path relative to project root, e.g. "src/features/sensor_pipeline.c".
112 pub path: &'static str,
113 /// C identifier stem used in the generated function name, e.g. "sensor_pipeline".
114 pub unit_name: &'static str,
115 /// TODO comment inserted into the function body.
116 pub todo_line: &'static str,
117}
118
119/// Static, fully-baked definition of a project-wizard template (catalog entry).
120pub struct WizardTemplateDefinition {
121 /// Template identifier this definition describes.
122 pub id: WizardTemplateId,
123 /// Human-readable display name.
124 pub label: &'static str,
125 /// One-line summary of what the template scaffolds.
126 pub description: &'static str,
127 /// SDK libraries the template depends on.
128 pub libs: &'static [&'static str],
129 /// Feature flags to emit, or `None` when the template needs none.
130 pub features: Option<WizardFeatureFlags>,
131 /// Extra `prj.conf` lines appended verbatim.
132 pub prj_conf_extras: &'static [&'static str],
133 /// Feature C files generated alongside `main`.
134 pub feature_files: &'static [FeatureFileSpec],
135 /// First line emitted in the generated `main` body.
136 pub body_line1: &'static str,
137 /// Second line emitted in the generated `main` body.
138 pub body_line2: &'static str,
139 /// Explanation lines surfaced to the user after scaffolding.
140 pub explanation: &'static [&'static str],
141}
142
143/// Static, fully-baked definition of a module-scaffold template (catalog entry).
144pub struct ModuleTemplateDefinition {
145 /// Module template identifier this definition describes.
146 pub id: ModuleTemplateId,
147 /// Human-readable display name.
148 pub label: &'static str,
149 /// One-line summary of what the module scaffolds.
150 pub description: &'static str,
151 /// Prefix applied to generated function names.
152 pub function_prefix: &'static str,
153 /// Lines may contain `{nm}` which is substituted with the normalized module name.
154 pub explanation: &'static [&'static str],
155}
156
157// ---------------------------------------------------------------------------
158// Plan I/O types
159// ---------------------------------------------------------------------------
160
161/// Inputs needed to plan a project scaffold from a wizard template.
162pub struct WizardPlanInput {
163 /// Template to scaffold from.
164 pub template_id: WizardTemplateId,
165 /// Project name used in generated identifiers and paths.
166 pub project_name: String,
167 /// Target directory the plan is rooted at.
168 pub destination: String,
169 /// Optional SoM SKU to write into board.yaml; defaults when None.
170 pub som_sku: Option<String>,
171}
172
173/// A single file a plan will emit: its path relative to the destination and its full content.
174pub struct WizardPlannedFile {
175 /// Path relative to the plan destination root.
176 pub relative_path: String,
177 /// Full file content to write.
178 pub content: String,
179}
180
181/// The full set of files a wizard template expands into, before any disk I/O.
182pub struct WizardPlan {
183 /// Template the plan was produced from.
184 pub template_id: WizardTemplateId,
185 /// Files to write, in emit order.
186 pub files: Vec<WizardPlannedFile>,
187}
188
189// ---------------------------------------------------------------------------
190// File-change tracking
191// ---------------------------------------------------------------------------
192
193/// Outcome of comparing a planned file against what is already on disk.
194#[derive(Debug, Clone, Copy, PartialEq, Eq)]
195pub enum WizardFileChangeKind {
196 /// File does not yet exist and will be created.
197 New,
198 /// File exists with different content and will be overwritten.
199 Update,
200 /// File exists with identical content; no write needed.
201 Unchanged,
202}
203
204impl WizardFileChangeKind {
205 /// Returns the stable lowercase label for this change kind.
206 pub fn as_str(self) -> &'static str {
207 match self {
208 WizardFileChangeKind::New => "new",
209 WizardFileChangeKind::Update => "update",
210 WizardFileChangeKind::Unchanged => "unchanged",
211 }
212 }
213}
214
215impl fmt::Display for WizardFileChangeKind {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 write!(f, "{}", self.as_str())
218 }
219}
220
221/// A planned file paired with how it differs from the current on-disk state.
222pub struct WizardFileChange {
223 /// Path relative to the plan destination root.
224 pub relative_path: String,
225 /// Classification of the change against disk.
226 pub kind: WizardFileChangeKind,
227}
228
229/// Summary of a plan applied to disk: which files were written vs. left untouched.
230pub struct WizardWriteResult {
231 /// Relative paths that were created or overwritten.
232 pub written: Vec<String>,
233 /// Relative paths skipped because their content already matched.
234 pub unchanged: Vec<String>,
235}
236
237// ---------------------------------------------------------------------------
238// Module scaffold types
239// ---------------------------------------------------------------------------
240
241/// Inputs needed to plan a module scaffold from a module template.
242pub struct ModuleScaffoldInput {
243 /// Module template to scaffold from.
244 pub template_id: ModuleTemplateId,
245 /// Raw module name as provided by the caller (normalized during planning).
246 pub module_name: String,
247 /// Target directory the plan is rooted at.
248 pub destination: String,
249}
250
251/// The set of files a module template expands into, with the normalized name resolved.
252pub struct ModuleScaffoldPlan {
253 /// Template the plan was produced from.
254 pub template_id: ModuleTemplateId,
255 /// Module name after normalization, substituted into generated content.
256 pub normalized_name: String,
257 /// Files to write, in emit order.
258 pub files: Vec<WizardPlannedFile>,
259}