better_config_loader/
yml.rs1use better_config_core::{AbstractConfig, Error};
2use std::collections::HashMap;
3use std::fs;
4
5pub trait YmlConfig<T = HashMap<String, String>>: AbstractConfig<T> {
7 fn load(target: Option<String>) -> Result<T, Error>
15 where
16 T: Default,
17 HashMap<String, String>: Into<T>,
18 Self: Sized,
19 {
20 let target = target.or(Some("config.yml".to_string()));
21
22 let mut yaml_map = HashMap::new();
23
24 if let Some(target) = target {
25 let file_paths: Vec<String> = target
26 .split(',')
27 .map(|s| s.trim().to_string())
28 .filter(|s| !s.is_empty())
29 .collect();
30
31 for file_path in file_paths {
32 let content = fs::read_to_string(&file_path).map_err(|e| Error::LoadFileError {
33 name: file_path.clone(),
34 source: Some(Box::new(e)),
35 })?;
36
37 let value: serde_yml::Value = serde_yml::from_str(&content).map_err(|e| Error::LoadFileError {
38 name: file_path.clone(),
39 source: Some(Box::new(e)),
40 })?;
41
42 flatten_yml_value(&value, None, &mut yaml_map);
43 }
44 }
45
46 Ok(yaml_map.into())
47 }
48}
49
50fn flatten_yml_value(value: &serde_yml::Value, parent_key: Option<String>, map: &mut HashMap<String, String>) {
51 match value {
52 serde_yml::Value::Mapping(obj) => {
53 for (key, val) in obj {
54 let key_str = match key {
55 serde_yml::Value::String(s) => s.clone(),
56 _ => serde_yml::to_string(key).unwrap_or_default(),
57 };
58 let new_key = match &parent_key {
59 Some(parent) => format!("{}.{}", parent, key_str),
60 None => key_str,
61 };
62 flatten_yml_value(val, Some(new_key), map);
63 }
64 }
65 serde_yml::Value::Sequence(arr) => {
66 for (i, val) in arr.iter().enumerate() {
67 let new_key = match &parent_key {
68 Some(parent) => format!("{}[{}]", parent, i),
69 None => i.to_string(),
70 };
71 flatten_yml_value(val, Some(new_key), map);
72 }
73 }
74 serde_yml::Value::String(s) => {
75 if let Some(key) = parent_key {
76 map.insert(key, s.to_string());
77 }
78 }
79 serde_yml::Value::Number(n) => {
80 if let Some(key) = parent_key {
81 if n.is_i64() {
82 map.insert(key, n.as_i64().unwrap().to_string());
83 } else if n.is_f64() {
84 map.insert(key, n.as_f64().unwrap().to_string());
85 } else {
86 map.insert(key, n.to_string());
87 }
88 }
89 }
90 serde_yml::Value::Bool(b) => {
91 if let Some(key) = parent_key {
92 map.insert(key, b.to_string());
93 }
94 }
95 serde_yml::Value::Null => {}
96 _ => {}
97 }
98}