string_config_parser/
lib.rs

1// Import necessary libraries and modules
2use std::collections::HashMap;
3use std::fs::File;
4use std::io::{BufRead, BufReader, Error, ErrorKind};
5use std::str::FromStr;
6
7// Define a public struct `Config` with fields for configuration options
8#[derive(Debug, Default)]
9pub struct Config<T> {
10    fields: HashMap<String, T>,
11}
12
13// Implement methods for the `Config` struct
14impl<T> Config<T>
15where
16    T: std::fmt::Debug + Default + FromStr,
17    <T as FromStr>::Err: std::fmt::Debug,
18{
19    // Define a method to create a `Config` instance from a file
20    pub fn from_file(file_path: &str) -> Result<Config<T>, Error> {
21        // Attempt to open the specified file
22        let file = File::open(file_path)?;
23
24        // Create a default `Config` instance
25        let mut config = Config::default();
26
27        // Define characters that indicate comments in the configuration file
28        let mut comment_chars = vec!['#', ';'];
29
30        // Iterate over each line in the file
31        for line in BufReader::new(file).lines() {
32            // Unwrap the line, handling any potential errors
33            let line = line?;
34            // Trim leading and trailing whitespaces from the line
35            let trimmed_line = line.trim();
36
37            // Skip empty lines and lines starting with comment characters
38            if !trimmed_line.is_empty()
39                && !comment_chars.contains(&trimmed_line.chars().next().unwrap())
40            {
41                // Split the line into key-value parts based on the '=' character
42                let parts: Vec<&str> = trimmed_line.split('=').map(|s| s.trim()).collect();
43
44                // Ensure that there are exactly two parts (key and value)
45                if parts.len() != 2 {
46                    return Err(Error::new(
47                        ErrorKind::InvalidData,
48                        "Invalid configuration format",
49                    ));
50                }
51
52                // Extract key and value
53                let key = parts[0].to_string();
54                let value_str = parts[1].trim_matches('"'); // Remove surrounding double quotes
55
56                // Use Default::default() for the default value
57                let value = if value_str.is_empty() {
58                    Default::default()
59                } else {
60                    value_str
61                        .parse()
62                        .map_err(|_| Error::new(ErrorKind::InvalidData, "Failed to parse value"))?
63                };
64
65                config.fields.insert(key, value);
66            }
67        }
68
69        // Return the populated `Config` instance
70        Ok(config)
71    }
72
73    // Define a method to get the value of using the `key`
74    pub fn get_value(&self, key: &str) -> Option<&T> {
75        self.fields.get(key)
76    }
77}