Skip to main content

rskit_cli/render/
keyvalue.rs

1//! Key-value display for headers and summaries.
2
3use std::fmt;
4
5/// Key-value display for headers/summaries.
6pub struct OutputKV {
7    pairs: Vec<(String, String)>,
8}
9
10impl OutputKV {
11    /// Create an empty key-value output block.
12    #[must_use]
13    pub const fn new() -> Self {
14        Self { pairs: Vec::new() }
15    }
16
17    /// Add a key-value pair to the output block.
18    pub fn add(&mut self, key: impl Into<String>, value: impl Into<String>) -> &mut Self {
19        self.pairs.push((key.into(), value.into()));
20        self
21    }
22}
23
24impl Default for OutputKV {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl fmt::Display for OutputKV {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        let max_key = self
33            .pairs
34            .iter()
35            .map(|(k, _)| k.chars().count())
36            .max()
37            .unwrap_or(0);
38        for (key, value) in &self.pairs {
39            writeln!(f, "  {key:>max_key$}:  {value}")?;
40        }
41        Ok(())
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::OutputKV;
48
49    #[test]
50    fn output_kv_renders() {
51        let mut kv = OutputKV::new();
52        kv.add("Output", "/tmp/dataset");
53        kv.add("Preset", "image");
54        let output = kv.to_string();
55        assert!(output.contains("Output"));
56        assert!(output.contains("/tmp/dataset"));
57    }
58}