[Rust] Properties To YAML Parser

[Rust] Properties To YAML Parser

BIGGUN 32 2022-09-03

背景

最近有个公司有个迁移配置的需求,要将原来项目中的配置迁移到内部的配置中心,需要把 *.properties 转化为 *.yml 来用,本着节约时间能写代码绝不动手的原则(事实证明比手动改格式更费时间 qwq),练练手写个 parser

Show me the code

use std::{cell::RefCell, collections::HashMap, rc::Rc, time};

mod test;

type Res = Result<(), Box<dyn std::error::Error>>;
type Ptr<T> = Rc<RefCell<T>>;

fn main() -> Res {
    let now = time::Instant::now();
    let conf = to_ptr(Prop {
        name: String::from("parent"),
        val: None,
        sub: Some(HashMap::new()),
    });

    let path = "./resource/test.properties";
    let prop_file = std::fs::read_to_string(path)?;
    for line in prop_file.lines() {
        let line = line.replace(" ", "");
        if line.len() != 0 && line.get(0..=0).unwrap() != "#" {
            parse(line.clone(), conf.clone());
        }
    }

    println!("{:?}", conf);

    let yaml = to_yaml(conf, 0);
    println!("result: \n{yaml}");
    println!("parse spend: {:?}", now.elapsed());

    Ok(())
}

fn to_yaml(conf: Rc<RefCell<Prop>>, dep: usize) -> String {
    let mut res = "".to_string();
    if let Some(map) = conf.borrow().sub.as_ref() {
        if map.len() != 0 {
            let sub_str = if dep != 0 {
                format!("{}{}: \n", "  ".repeat(dep - 1), conf.borrow().name.clone())
            } else {
                "".to_string()
            };
            for (_, sub_prop) in map.iter() {
                res = format!("{}{}", res, to_yaml(sub_prop.clone(), dep + 1));
            }
            res = format!("{sub_str}{res}");
        } else {
            res = format!("{}{}: {}\n", "  ".repeat(dep - 1), conf.borrow().name.clone(), conf.borrow().val.clone().unwrap());
        }
    }

    if dep == 1 {
        format!("{res}\n")
    } else {
        format!("{res}")
    }
}

fn to_ptr<T>(ele: T) -> Ptr<T> {
    Rc::new(RefCell::new(ele))
}

#[derive(Debug)]
struct Prop {
    name: String,
    val: Option<String>,
    sub: Option<HashMap<String, Ptr<Prop>>>,
}

fn parse(line: String, father: Ptr<Prop>) -> Option<Ptr<Prop>>{
    if let None = line.find("=") {
        return None;
    }

    let mut ptr: Ptr<Prop> = to_ptr(Prop {
        name: String::new(),
        val: None,
        sub: None,
    });

    for (idx, c) in line.chars().enumerate() {
        if c == '.' || c == '=' {
            let (name, suffix) = line.split_at(idx);
            let name = String::from(name);
            if let Some(ref mut map) = father.borrow_mut().sub {
                match map.get(&name) {
                    Some(val) => {
                        ptr = val.clone();
                    }
                    None => {
                        ptr.borrow_mut().name = name.clone();
                        ptr.borrow_mut().sub = Some(HashMap::new());
                        map.insert(name.clone(), ptr.clone());
                    }
                };
            }

            match suffix.get(0..=0) {
                Some(".") => {
                    parse(suffix.get(1..).unwrap().to_owned(), ptr.clone()); 
                }
                Some("=") => {
                    ptr.borrow_mut().val = match suffix.get(1..) {
                        Some(val) => Some(String::from(val)),
                        None => Some(String::new()),
                    };
                }
                _ => {}
            };

            break;
        }
    }

    Some(ptr.clone())
}

总结

优雅是不可能优雅的,能力就是这个样子,能跑就行是我们的人生信条 =v=