espforge_lib/nibblers/
components.rs1use crate::{
2 config::EspforgeConfiguration,
3 nibblers::{ConfigNibbler, NibblerResult, NibblerStatus},
4 register_nibbler,
5};
6use espforge_macros::auto_register_nibbler;
7use serde_yaml_ng::Value;
8
9#[derive(Default)]
10#[auto_register_nibbler]
11pub struct ComponentNibbler;
12
13impl ConfigNibbler for ComponentNibbler {
14 fn name(&self) -> &str {
15 "ComponentNibbler"
16 }
17
18 fn priority(&self) -> u8 {
19 20
20 }
21
22 fn process(&self, config: &EspforgeConfiguration) -> Result<NibblerResult, String> {
23 let components = match &config.components {
24 Some(comps) => comps,
25 None => return Ok(self.empty_result()),
26 };
27
28 let (findings, status) = self.validate_components(components, config);
29
30 Ok(NibblerResult {
31 nibbler_name: self.name().to_string(),
32 findings,
33 status,
34 })
35 }
36}
37
38impl ComponentNibbler {
39 fn empty_result(&self) -> NibblerResult {
40 NibblerResult {
41 nibbler_name: self.name().to_string(),
42 findings: Vec::new(),
43 status: NibblerStatus::Ok,
44 }
45 }
46
47 fn validate_components(
48 &self,
49 components: &std::collections::HashMap<String, crate::config::ComponentConfig>,
50 config: &EspforgeConfiguration,
51 ) -> (Vec<String>, NibblerStatus) {
52 let mut findings = Vec::new();
53 let mut has_errors = false;
54
55 for (comp_name, comp_config) in components {
56 findings.push(format!(
57 "Checking component '{}' (using {})",
58 comp_name, comp_config.using
59 ));
60
61 has_errors |=
62 self.validate_component_references(comp_name, comp_config, config, &mut findings);
63 }
64
65 let status = if has_errors {
66 NibblerStatus::Error
67 } else {
68 NibblerStatus::Ok
69 };
70
71 (findings, status)
72 }
73
74 fn validate_component_references(
75 &self,
76 comp_name: &str,
77 comp_config: &crate::config::ComponentConfig,
78 config: &EspforgeConfiguration,
79 findings: &mut Vec<String>,
80 ) -> bool {
81 let mut has_errors = false;
82
83 for (key, value) in &comp_config.with {
84 if let Some(ref_name) = self.extract_reference(value) {
85 if self.is_valid_reference(ref_name, config) {
86 findings.push(format!(" Validated reference '${}'", ref_name));
87 } else {
88 findings.push(format!(
89 " Error: Component '{}' references undefined hardware resource '${}' in property '{}'",
90 comp_name, ref_name, key
91 ));
92 has_errors = true;
93 }
94 }
95 }
96
97 has_errors
98 }
99
100 fn extract_reference<'a>(&self, value: &'a Value) -> Option<&'a str> {
101 match value {
102 Value::String(s) => s.strip_prefix('$'),
103 _ => None,
104 }
105 }
106
107 fn is_valid_reference(&self, ref_name: &str, config: &EspforgeConfiguration) -> bool {
108 config
109 .esp32
110 .as_ref()
111 .map(|esp32| {
112 esp32.gpio.contains_key(ref_name)
113 || esp32.spi.contains_key(ref_name)
114 || esp32.i2c.contains_key(ref_name)
115 || esp32.uart.contains_key(ref_name)
116 })
117 .unwrap_or(false)
118 }
119}