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}