dev_tool/
conf_util.rs

1use crate::FileUtil;
2use serde_json::Value;
3use std::io;
4use std::path::Path;
5
6#[derive(Debug)]
7pub struct JsonWrapper {
8    pub file_path: String,
9    pub raw_data: String,
10    pub data: Value,
11}
12
13pub struct ValueWrapper<'a> {
14    value: &'a Value,
15}
16
17impl<'a> ValueWrapper<'a> {
18    /// 创建一个新的实例
19    ///
20    /// # 参数
21    /// * `value` - 指向Value的引用
22    ///
23    /// # 返回值
24    /// 返回包含指定value的新实例
25    pub fn new(value: &'a Value) -> Self {
26        Self { value }
27    }
28
29    /// 根据键名获取对应的值
30    ///
31    /// 该函数支持通过点号分隔的多层键名来访问嵌套的数据结构,
32    /// 也支持在数组中查找指定键名的值。
33    ///
34    /// # 参数
35    /// * `key` - 要查找的键名,可以是单层键名或点号分隔的多层键名
36    ///
37    /// # 返回值
38    /// 返回包含查找到的值的向量,如果未找到则包含Null值
39    pub fn get(&self, key: &'a str) -> Vec<&'a Value> {
40        let mut results = Vec::new();
41        if let Some((left, right)) = key.split_once(".") {
42            // 处理多层键名的情况
43            let x = self.value.get(left);
44            if x.is_none() {
45                results.push(&Value::Null);
46            } else {
47                let x = x.unwrap();
48                let next = ValueWrapper::new(x);
49                results.append(&mut next.get(right));
50            }
51        } else {
52            // 处理单层键名的情况
53            match self.value {
54                Value::Object(map) => {
55                    // 在对象中查找键名
56                    if let Some(v) = map.get(key) {
57                        results.push(v);
58                    } else {
59                        results.push(&Value::Null);
60                    }
61                }
62                Value::Array(vec) => {
63                    // 在数组的每个元素中查找键名
64                    for item in vec {
65                        match item.get(key) {
66                            Some(v) => results.push(v),
67                            None => results.push(&Value::Null),
68                        }
69                    }
70                }
71                _ => results.push(&Value::Null),
72            }
73        }
74        results
75    }
76}
77
78impl JsonWrapper {
79    /// 创建一个新的配置实例
80    ///
81    /// 该函数会读取指定路径的配置文件,解析JSON格式的内容,并创建配置对象
82    ///
83    /// # 参数
84    /// * `file_path` - 配置文件的路径字符串引用
85    ///
86    /// # 返回值
87    /// 返回Result类型,成功时包含配置实例,失败时包含IO错误
88    ///
89    /// # 错误
90    /// 当文件读取失败或JSON解析失败时会返回相应的错误
91    pub fn new(file_path: &str) -> io::Result<Self> {
92        // 读取配置文件内容
93        let conf_string = FileUtil::read_string(Path::new(file_path))?;
94        // 解析JSON数据
95        let data: Value = serde_json::from_str(&conf_string)?;
96        Ok(Self {
97            file_path: file_path.to_string(),
98            raw_data: conf_string,
99            data,
100        })
101    }
102
103    /// 获取指定键对应的值列表
104    ///
105    /// 该函数通过创建一个值包装器来访问内部数据,并返回与给定键关联的所有值。
106    ///
107    /// # 参数
108    /// * `key` - 要查找的静态字符串键
109    ///
110    /// # 返回值
111    /// 返回一个包含所有匹配值的引用向量
112    pub fn get<'a, 'b: 'a>(&'a self, key: &'b str) -> Vec<&'a Value> {
113        let wrapper = ValueWrapper::new(&self.data);
114        wrapper.get(key)
115    }
116
117    /// 获取指定键对应的第一个值
118    ///
119    /// # 参数
120    /// * `key` - 要查找的键名,必须是静态字符串
121    ///
122    /// # 返回值
123    /// 返回键对应值的引用
124    ///
125    /// # 注意
126    /// 如果键不存在或对应的值为空,会触发panic
127    pub fn get_one<'a, 'b: 'a>(&'a self, key: &'b str) -> &'a Value {
128        // 该方法注释,要求b的生命周期不小于a的生命周期
129        // 创建值包装器来处理数据查询
130        let wrapper = ValueWrapper::new(&self.data);
131        // 获取指定键对应的值向量
132        let vec = wrapper.get(key);
133        // 返回向量中的第一个值,如果不存在则panic
134        vec.first().unwrap()
135    }
136}
137
138#[cfg(test)]
139mod tests {
140
141    use super::*;
142
143    #[test]
144    fn test_json_conf_util() {
145        
146        let json_wrapper = JsonWrapper::new("docs/config.json").unwrap();
147
148        let x = json_wrapper.get("name");
149        // name = [String("Alice")]
150        println!("name = {:?}", x);
151
152        let x = json_wrapper.get("age");
153        // age = [Number(30)]
154        println!("age = {:?}", x);
155
156        let x = json_wrapper.get("is_student");
157        // is_student = [Bool(false)]
158        println!("is_student = {:?}", x);
159
160        let x = json_wrapper.get("hobbies");
161        // hobbies = [Array [String("reading"), String("swimming"), String("cooking")]]
162        println!("hobbies = {:?}", x);
163
164        let x = json_wrapper.get("address");
165        // address = [Object {"children": Array [Object {"age": Number(5), "name": String("r")}, Object {"age": Number(6), "name": String("s")}], "city": String("New York"), "releases": Array [String("v1"), String("v2")], "state": String("NY"), "street": String("123 Main St"), "x": Object {"y": String("hello, json!")}, "zip": String("10001")}]
166        println!("address = {:?}", x);
167
168        let x = json_wrapper.get("address.street");
169        // address.street = [String("123 Main St")]
170        println!("address.street = {:?}", x);
171
172        let x = json_wrapper.get("address.releases");
173        // address.releases = [Array [String("v1"), String("v2")]]
174        println!("address.releases = {:?}", x);
175
176        let x = json_wrapper.get("address.x.y");
177        // address.x.y = [String("hello, json!")]
178        println!("address.x.y = {:?}", x);
179
180        let x = json_wrapper.get("address.children.name");
181        // address.children.name = [String("r"), String("s")]
182        println!("address.children.name = {:?}", x);
183        println!("=============================================================");
184
185        let name = json_wrapper.get_one("name").as_str().unwrap();
186        let age = json_wrapper.get_one("age").as_i64().unwrap();
187        println!("name = {:?}", name);
188        println!("age = {:?}", age);
189
190        let key = String::from("address.x.y");
191        let x = json_wrapper.get_one(&key).as_str().unwrap();
192        // address.x.y = hello, json!
193        println!("address.x.y = {}", x);
194
195    }
196}