Skip to main content

sim_config/
report.rs

1//! Report model for effective config provenance.
2
3use sim_kernel::Symbol;
4
5use crate::{ConfigSource, EffectiveConfig};
6
7/// User-facing summary of field provenance in an effective config.
8#[derive(Clone, Debug, Default, PartialEq, Eq)]
9pub struct ConfigReport {
10    /// Provenance entries, one per effective top-level field.
11    pub entries: Vec<ConfigReportEntry>,
12}
13
14impl ConfigReport {
15    /// Builds a report from an effective config.
16    pub fn from_effective(effective: &EffectiveConfig) -> Self {
17        Self {
18            entries: effective
19                .trace
20                .iter()
21                .map(|trace| ConfigReportEntry {
22                    lib: trace.lib.clone(),
23                    key: trace.key.clone(),
24                    source: source_label(&trace.source),
25                })
26                .collect(),
27        }
28    }
29}
30
31/// One field's effective source label.
32#[derive(Clone, Debug, PartialEq, Eq)]
33pub struct ConfigReportEntry {
34    /// Library table that contains the field.
35    pub lib: Symbol,
36    /// Top-level field key.
37    pub key: String,
38    /// Human-readable source label.
39    pub source: String,
40}
41
42fn source_label(source: &ConfigSource) -> String {
43    match source {
44        ConfigSource::BuiltIn { lib } => format!("built-in:{}", lib.as_qualified_str()),
45        ConfigSource::Probe { probe, mode } => {
46            format!("probe:{}:{mode:?}", probe.as_qualified_str())
47        }
48        ConfigSource::HomeFile { path } => format!("home-file:{}", path.display()),
49        ConfigSource::WorkFile { path } => format!("work-file:{}", path.display()),
50        ConfigSource::SingleFile { path } => format!("single-file:{}", path.display()),
51        ConfigSource::Site { site } => format!("site:{}", site.as_qualified_str()),
52        ConfigSource::Explicit { label } => format!("explicit:{label}"),
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use sim_kernel::Symbol;
59    use sim_value::build::{map, text};
60
61    use crate::{ConfigDir, ConfigLayer, merge_layers};
62
63    use super::*;
64
65    #[test]
66    fn report_projects_trace_entries() {
67        let lib = Symbol::qualified("sim", "cookbook");
68        let dir = ConfigDir::one(lib.clone(), map(vec![("mode", text("built-in"))])).unwrap();
69        let effective = merge_layers(&[ConfigLayer::new(
70            ConfigSource::BuiltIn { lib: lib.clone() },
71            dir,
72        )]);
73
74        let report = ConfigReport::from_effective(&effective);
75
76        assert_eq!(
77            report.entries,
78            vec![ConfigReportEntry {
79                lib,
80                key: "mode".to_owned(),
81                source: "built-in:sim/cookbook".to_owned()
82            }]
83        );
84    }
85}