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