Skip to main content

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}