AzLearn

تمرين إعادة البناء

Config Loader

أعد كتابة قارئ إعدادات key=value مع قيم افتراضية وتحقق بسيط.

rust ~20 دقيقة متوسط
أعد بناء الكود Rebuild

هذا هو الكود. اكتبه بنفسك.

الكود المرجعي
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::io;

#[derive(Debug)]
struct Config {
    host: String,
    port: u16,
    debug: bool,
}

fn main() -> io::Result<()> {
    let path = env::args()
        .nth(1)
        .unwrap_or_else(|| "app.conf".to_string());
    let text = fs::read_to_string(path).unwrap_or_else(|_| sample_config());
    let values = parse_key_values(&text);
    let config = Config::from_values(&values);

    println!("host={}", config.host);
    println!("port={}", config.port);
    println!("debug={}", config.debug);

    Ok(())
}

impl Config {
    fn from_values(values: &BTreeMap<String, String>) -> Self {
        Self {
            host: values
                .get("host")
                .cloned()
                .unwrap_or_else(|| "127.0.0.1".to_string()),
            port: values
                .get("port")
                .and_then(|value| value.parse().ok())
                .filter(|port| *port > 0)
                .unwrap_or(8080),
            debug: values
                .get("debug")
                .map(|value| matches!(value.as_str(), "true" | "1" | "yes"))
                .unwrap_or(false),
        }
    }
}

fn parse_key_values(text: &str) -> BTreeMap<String, String> {
    let mut values = BTreeMap::new();

    for line in text.lines() {
        let line = line.trim();
        if line.is_empty() || line.starts_with('#') {
            continue;
        }

        if let Some((key, value)) = line.split_once('=') {
            values.insert(key.trim().to_string(), value.trim().to_string());
        }
    }

    values
}

fn sample_config() -> String {
    "host=0.0.0.0\nport=3000\ndebug=true\n".to_string()
}
اكتب هنا