better_config_loader/
json.rs1use better_config_core::{AbstractConfig, Error};
2use better_config_core::misc;
3use std::collections::HashMap;
4use std::fs;
5
6pub trait JsonConfig<T = HashMap<String, String>>: AbstractConfig<T> {
8 fn load(target: Option<String>) -> Result<T, Error>
16 where
17 T: Default,
18 HashMap<String, String>: Into<T>,
19 Self: Sized,
20 {
21 let target = target.or(Some("config.json".to_string()));
22
23 let mut json_map = HashMap::new();
24
25 if let Some(target) = target {
26 let file_paths = misc::validate_and_split_paths(&target)?;
27
28 for file_path in file_paths {
29 misc::check_file_accessibility(&file_path)?;
31
32 let content = fs::read_to_string(&file_path)
33 .map_err(|e| Error::IoError {
34 operation: format!("read file '{}'", file_path),
35 source: Some(Box::new(e)),
36 })?;
37
38 let value: serde_json::Value = serde_json::from_str(&content)
39 .map_err(|e| Error::parse_json_error(&file_path, e))?;
40
41 flatten_json_value(&value, None, &mut json_map)
42 .map_err(|e| Error::value_conversion_error("json", "string", &format!("{}", e)))?;
43 }
44 }
45
46 Ok(json_map.into())
47 }
48}
49
50fn flatten_json_value(value: &serde_json::Value, parent_key: Option<String>, map: &mut HashMap<String, String>) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
51 match value {
52 serde_json::Value::Object(obj) => {
53 for (key, val) in obj {
54 let new_key = match &parent_key {
55 Some(parent) => format!("{}.{}", parent, key),
56 None => key.to_string(),
57 };
58 flatten_json_value(val, Some(new_key), map)?;
59 }
60 }
61 serde_json::Value::Array(arr) => {
62 for (i, val) in arr.iter().enumerate() {
63 let new_key = match &parent_key {
64 Some(parent) => format!("{}[{}]", parent, i),
65 None => i.to_string(),
66 };
67 flatten_json_value(val, Some(new_key), map)?;
68 }
69 }
70 serde_json::Value::String(s) => {
71 if let Some(key) = parent_key {
72 map.insert(key, s.to_string());
73 }
74 }
75 serde_json::Value::Number(n) => {
76 if let Some(key) = parent_key {
77 let num_str = if n.is_i64() {
78 n.as_i64()
79 .map(|v| v.to_string())
80 .unwrap_or_else(|| n.to_string())
81 } else if n.is_f64() {
82 n.as_f64()
83 .map(|v| v.to_string())
84 .unwrap_or_else(|| n.to_string())
85 } else {
86 n.to_string()
87 };
88 map.insert(key, num_str);
89 }
90 }
91 serde_json::Value::Bool(b) => {
92 if let Some(key) = parent_key {
93 map.insert(key, b.to_string());
94 }
95 }
96 serde_json::Value::Null => {}
97 }
98
99 Ok(())
100}