1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use anyhow::{anyhow, Context};
use std::collections::VecDeque;

pub fn extract(pattern: &str, manifest: toml::Table) -> anyhow::Result<String> {
    let parts: VecDeque<_> = pattern.split('.').map(ToString::to_string).collect();
    handle(parts, toml::Value::Table(manifest))
}

fn handle(parts: VecDeque<String>, value: toml::Value) -> anyhow::Result<String> {
    let mut parts = parts;
    match value {
        toml::Value::String(value) => Ok(value.to_string()),
        toml::Value::Integer(value) => Ok(value.to_string()),
        toml::Value::Float(value) => Ok(value.to_string()),
        toml::Value::Boolean(value) => Ok(value.to_string()),
        toml::Value::Datetime(value) => Ok(value.to_string()),
        toml::Value::Array(value) => {
            if let Some(first) = parts.pop_front() {
                if let Ok(index) = first.parse::<usize>() {
                    handle(
                        parts,
                        value
                            .get(index)
                            .with_context(|| format!("Array index out of bounds {index}"))?
                            .clone(),
                    )
                } else {
                    Err(anyhow!("Failed to parse {first} into an array index"))
                }
            } else {
                let stringified = value
                    .iter()
                    .map(|val| handle(VecDeque::new(), val.clone()).expect("Ouch 1"))
                    .collect::<Vec<_>>()
                    .join("\n");
                Ok(stringified)
            }
        }
        toml::Value::Table(value) => {
            if let Some(first) = parts.pop_front() {
                let v = value
                    .get(&first)
                    .with_context(|| format!("No such key found {first}"))?;
                handle(parts, v.clone())
            } else {
                let stringified = value
                    .iter()
                    .map(|entry| {
                        let value = handle(VecDeque::new(), entry.1.clone()).expect("Ouch 2");
                        format!("{} = {value}", entry.0)
                    })
                    .collect::<Vec<_>>()
                    .join("\n");
                Ok(stringified)
            }
        }
    }
}