mitoo 0.3.0

mitoo is a Rust toolkit library that encapsulates methods such as configuration reading, file operations, encryption and decryption, transcoding, regular expressions, threading, collections, trees, sqlite, rabbitMQ, etc., and customizes or integrates various Util tool classes.
Documentation
use crate::FileUtil;
use serde_json::Value;
use std::io;
use std::path::Path;

/// Json configuration reading
/// ```rust
/// use mitoo::JsonWrapper;
/// 
/// #[test]
/// fn test_config_util() {
///    // read the configuration file
///     let wrapper = JsonWrapper::new("docs/config.json").unwrap();
///     // Directly convert the json string into JsonWrapper
///     // let warpper = JsonWrapper::from_string("......").unwrap();
/// 
///     // Whether it is an Object or an array, they as directly operated using the . (dot).
///     // Here, "address" is an object, "children" is an array, and "name" is an attribute of the objects within the "children" array.
///     let x = wrapper.get("address.children.name");
///     println!("address.children.name = {:?}", x);
///     
///     // The get method is used to retrieve an array, while get_one is used to retrieve the first element.
///     let x = wrapper.get_one("address.x.y").as_str().unwrap();
///     println!("address.x.y = {}", x);
/// }
/// ```
#[derive(Debug)]
pub struct JsonWrapper {
    pub raw_data: String,
    pub data: Value,
}

pub struct ValueWrapper<'a> {
    value: &'a Value,
}

impl<'a> ValueWrapper<'a> {
    /// 创建一个新的实例
    ///
    /// # 参数
    /// * `value` - 指向Value的引用
    ///
    /// # 返回值
    /// 返回包含指定value的新实例
    pub fn new(value: &'a Value) -> Self {
        Self { value }
    }

    /// 根据键名获取对应的值
    ///
    /// 该函数支持通过点号分隔的多层键名来访问嵌套的数据结构,
    /// 也支持在数组中查找指定键名的值。
    ///
    /// # 参数
    /// * `key` - 要查找的键名,可以是单层键名或点号分隔的多层键名
    ///
    /// # 返回值
    /// 返回包含查找到的值的向量,如果未找到则包含Null值
    pub fn get(&self, key: &'a str) -> Vec<&'a Value> {
        let mut results = Vec::new();
        if let Some((left, right)) = key.split_once(".") {
            // 处理多层键名的情况
            let x = self.value.get(left);
            if x.is_none() {
                results.push(&Value::Null);
            } else {
                let x = x.unwrap();
                let next = ValueWrapper::new(x);
                results.append(&mut next.get(right));
            }
        } else {
            // 处理单层键名的情况
            match self.value {
                Value::Object(map) => {
                    // 在对象中查找键名
                    if let Some(v) = map.get(key) {
                        results.push(v);
                    } else {
                        results.push(&Value::Null);
                    }
                }
                Value::Array(vec) => {
                    // 在数组的每个元素中查找键名
                    for item in vec {
                        match item.get(key) {
                            Some(v) => results.push(v),
                            None => results.push(&Value::Null),
                        }
                    }
                }
                _ => results.push(&Value::Null),
            }
        }
        results
    }
}

impl JsonWrapper {
    /// 创建一个新的配置实例
    ///
    /// 该函数会读取指定路径的配置文件,解析JSON格式的内容,并创建配置对象
    ///
    /// # 参数
    /// * `file_path` - 配置文件的路径字符串引用
    ///
    /// # 返回值
    /// 返回Result类型,成功时包含配置实例,失败时包含IO错误
    ///
    /// # 错误
    /// 当文件读取失败或JSON解析失败时会返回相应的错误
    pub fn new(file_path: &str) -> io::Result<Self> {
        // 读取配置文件内容
        let conf_string = FileUtil::read_string(Path::new(file_path))?;
        // 解析JSON数据
        let data: Value = serde_json::from_str(&conf_string)?;
        Ok(Self {
            raw_data: conf_string,
            data,
        })
    }

    pub fn from_string(conf_string: &str) -> io::Result<Self> {
        let data: Value = serde_json::from_str(conf_string)?;
        Ok(Self {
            raw_data: conf_string.to_string(),
            data,
        })
    }

    /// 获取指定键对应的值列表
    ///
    /// 该函数通过创建一个值包装器来访问内部数据,并返回与给定键关联的所有值。
    ///
    /// # 参数
    /// * `key` - 要查找的静态字符串键
    ///
    /// # 返回值
    /// 返回一个包含所有匹配值的引用向量
    pub fn get<'a, 'b: 'a>(&'a self, key: &'b str) -> Vec<&'a Value> {
        let wrapper = ValueWrapper::new(&self.data);
        wrapper.get(key)
    }

    /// 获取指定键对应的第一个值
    ///
    /// # 参数
    /// * `key` - 要查找的键名,必须是静态字符串
    ///
    /// # 返回值
    /// 返回键对应值的引用
    ///
    /// # 注意
    /// 如果键不存在或对应的值为空,会触发panic
    pub fn get_one<'a, 'b: 'a>(&'a self, key: &'b str) -> &'a Value {
        // 该方法注释,要求b的生命周期不小于a的生命周期
        // 创建值包装器来处理数据查询
        let wrapper = ValueWrapper::new(&self.data);
        // 获取指定键对应的值向量
        let vec = wrapper.get(key);
        // 返回向量中的第一个值,如果不存在则panic
        vec.first().unwrap()
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_json_conf_util() {
        
        let json_wrapper = JsonWrapper::new("docs/config.json").unwrap();

        let x = json_wrapper.get("name");
        // name = [String("Alice")]
        println!("name = {:?}", x);

        let x = json_wrapper.get("age");
        // age = [Number(30)]
        println!("age = {:?}", x);

        let x = json_wrapper.get("is_student");
        // is_student = [Bool(false)]
        println!("is_student = {:?}", x);

        let x = json_wrapper.get("hobbies");
        // hobbies = [Array [String("reading"), String("swimming"), String("cooking")]]
        println!("hobbies = {:?}", x);

        let x = json_wrapper.get("address");
        // 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")}]
        println!("address = {:?}", x);

        let x = json_wrapper.get("address.street");
        // address.street = [String("123 Main St")]
        println!("address.street = {:?}", x);

        let x = json_wrapper.get("address.releases");
        // address.releases = [Array [String("v1"), String("v2")]]
        println!("address.releases = {:?}", x);

        let x = json_wrapper.get("address.x.y");
        // address.x.y = [String("hello, json!")]
        println!("address.x.y = {:?}", x);

        let x = json_wrapper.get("address.children.name");
        // address.children.name = [String("r"), String("s")]
        println!("address.children.name = {:?}", x);
        println!("=============================================================");

        let name = json_wrapper.get_one("name").as_str().unwrap();
        let age = json_wrapper.get_one("age").as_i64().unwrap();
        println!("name = {:?}", name);
        println!("age = {:?}", age);

        let key = String::from("address.x.y");
        let x = json_wrapper.get_one(&key).as_str().unwrap();
        // address.x.y = hello, json!
        println!("address.x.y = {}", x);

    }
}