espforge_lib/parse/
components.rs1use crate::parse::EspforgeConfiguration;
2use crate::parse::processor::SectionProcessor;
3use anyhow::{Context, Result, bail};
4use espforge_common::components::Component;
5use espforge_common::dependency::DependencyKind;
6use espforge_common::hardware::Esp32Config;
7use serde_yaml_ng::Value;
8use std::collections::HashMap;
9use espforge_common::codegen::find_plugin;
10
11pub struct ComponentProvisioner;
12
13impl SectionProcessor for ComponentProvisioner {
14 fn section_key(&self) -> &'static str {
15 "components"
16 }
17
18 fn priority(&self) -> u32 { 200 }
19
20 fn process(&self, content: &Value, model: &mut EspforgeConfiguration) -> Result<()> {
21 let components: HashMap<String, Component> = serde_yaml_ng::from_value(content.clone())
22 .context("Failed to deserialize components")?;
23
24 for (_name, _spec) in &components {
25 if let Some(esp32) = &model.esp32 {
27 self.validate(&components, esp32)?;
28 }
29 }
30
31 model.components.extend(components);
32 println!("✓ {} components provisioned", model.components.len());
33 Ok(())
34 }
35}
36
37impl ComponentProvisioner {
38 fn validate(&self, components: &HashMap<String, Component>, esp32: &Esp32Config) -> Result<()> {
39 for (name, spec) in components {
40 let plugin = find_plugin(&spec.driver)
41 .ok_or_else(|| anyhow::anyhow!("Unknown driver '{}' for component '{}'", spec.driver, name))?;
42
43 plugin.validate(&spec.properties)
45 .with_context(|| format!("Validation failed for component '{}'", name))?;
46
47 let deps = plugin.dependencies(&spec.properties)?;
49 for dep in deps {
50 if dep.kind == DependencyKind::Pin || dep.kind == DependencyKind::Peripheral {
51 let res_name = dep.name.strip_prefix('$').unwrap_or(&dep.name);
52
53 if !Self::hardware_exists(esp32, res_name) {
55 bail!("Component '{}' references unknown hardware resource '{}'", name, res_name);
56 }
57 }
58 }
59 }
60 Ok(())
61 }
62
63 fn hardware_exists(esp32: &Esp32Config, name: &str) -> bool {
64 esp32.gpio.contains_key(name) || esp32.spi.contains_key(name) ||
65 esp32.i2c.contains_key(name) || esp32.uart.contains_key(name)
66 }
67}