espforge_lib/resolver/strategies/
utils.rs

1use std::collections::HashMap;
2
3use crate::config::Esp32Config;
4use crate::resolver::strategies::ResolutionContext;
5use anyhow::{Result, anyhow};
6use serde::Serialize;
7use serde_yaml_ng::Value;
8
9pub trait ValueExt {
10    fn as_ref_name(&self) -> Result<&str>;
11}
12
13impl ValueExt for Value {
14    fn as_ref_name(&self) -> Result<&str> {
15        let s = self.as_str()
16            .ok_or_else(|| anyhow!("Reference must be a string"))?;
17        
18        s.strip_prefix('$')
19            .ok_or_else(|| anyhow!("Reference must start with '$', got: {}", s))
20    }
21}
22
23impl<'a> ResolutionContext<'a> {
24    pub fn hardware(&self) -> Result<&'a Esp32Config> {
25        self.hardware.ok_or_else(|| {
26            anyhow!("Hardware configuration (esp32) is missing")
27        })
28    }
29}
30
31pub fn resolve_hardware_resource<T, V, MapFn, ViewFn>(
32    value: &Value,
33    ctx: &ResolutionContext,
34    map_selector: MapFn,
35    view_converter: ViewFn,
36) -> Result<Value>
37where
38    MapFn: FnOnce(&Esp32Config) -> &HashMap<String, T>,
39    ViewFn: FnOnce(&T) -> V,
40    V: Serialize,
41{
42    let name = value.as_ref_name()?;
43    let hardware = ctx.hardware()?;
44    let map = map_selector(hardware);
45    let config = map.get(name)
46        .ok_or_else(|| anyhow!("Hardware resource '${}' not found", name))?;
47    let view = view_converter(config);
48    Ok(serde_yaml_ng::to_value(view)?)
49}