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
59
//! Yaml config source.
use yaml_rust::YamlLoader;

use super::{memory::ConfigSourceBuilder, ConfigSourceAdaptor, ConfigSourceParser};
use crate::ConfigError;

impl ConfigSourceAdaptor for yaml_rust::Yaml {
    fn convert_source(self, source: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError> {
        match self {
            yaml_rust::Yaml::Real(v) => source.insert(v),
            yaml_rust::Yaml::Integer(v) => source.insert(v),
            yaml_rust::Yaml::String(v) => source.insert(v),
            yaml_rust::Yaml::Boolean(v) => source.insert(v),
            yaml_rust::Yaml::Array(v) => source.insert_array(v)?,
            yaml_rust::Yaml::Hash(v) => source.insert_map(
                v.into_iter()
                    .filter_map(|(k, v)| k.as_str().map(|k| (k.to_string(), v))),
            )?,
            _ => {}
        }
        Ok(())
    }
}

impl ConfigSourceAdaptor for Yaml {
    fn convert_source(self, builder: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError> {
        for y in self.0 {
            y.convert_source(builder)?;
        }
        Ok(())
    }
}

impl ConfigSourceParser for Yaml {
    type Adaptor = Yaml;
    fn parse_source(content: &str) -> Result<Self::Adaptor, ConfigError> {
        Ok(Yaml(YamlLoader::load_from_str(content)?))
    }

    fn file_extensions() -> Vec<&'static str> {
        vec!["yaml", "yml"]
    }
}

/// Yaml source.
#[allow(missing_debug_implementations)]
pub struct Yaml(Vec<yaml_rust::Yaml>);

#[cfg(test)]
mod test {
    use super::*;
    use crate::{source::inline_source, test::source_test_suit};

    #[test]
    #[allow(unused_qualifications)]
    fn inline_test() -> Result<(), ConfigError> {
        source_test_suit(inline_source!("../../app.yaml")?)
    }
}