RMusicBot/src/confighandler.rs

204 lines
6 KiB
Rust

#![allow(dead_code)]
use std::fmt::Display;
use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::str::FromStr;
use std::collections::HashMap;
#[derive(Clone)]
pub enum Value {
Value(String),
Array(Vec<String>),
}
struct ConfigSection {
header: String,
body: HashMap<String, Value>,
}
impl Value {
pub fn empty() -> Value {
Value::Value("".to_string())
}
pub fn value<T>(value: &T) -> Value
where
T: Display,
{
Value::Value(format!("{}", value))
}
pub fn array<T>(array: &Vec<T>) -> Value
where
T: Display,
{
Value::Array(array.iter().map(|v| format!("{}", v)).collect())
}
pub fn set_value<T>(&self, value: &mut T) -> Result<(), String>
where
T: FromStr,
{
match self {
Value::Value(value_string) => match value_string.parse::<T>() {
Ok(val) => *value = val,
Err(_) => return Err(format!("error parsing value {}", value_string)),
},
_ => return Err("key_value has wrong format".to_string()),
};
Ok(())
}
pub fn set_array<T>(&self, array: &mut Vec<T>) -> Result<(), String>
where
T: FromStr,
{
match self {
Value::Array(value_array) => {
for value_string in value_array {
match value_string.parse::<T>() {
Ok(val) => array.push(val),
Err(_) => return Err(format!("error parsing value {}", value_string)),
}
}
}
_ => return Err("key_value has wrong format".to_string()),
};
Ok(())
}
}
pub fn read_config(file_name: &str) -> Result<HashMap<String, HashMap<String, Value>>, String> {
let file = match File::open(file_name) {
Ok(file) => file,
Err(msg) => return Err(format!("error opening config file({}): {}", file_name, msg)),
};
let mut infos = HashMap::new();
let mut current_section: Option<ConfigSection> = None;
for line_res in BufReader::new(file).lines() {
if let Ok(line) = line_res {
let mut trimmed = line.trim().to_string();
if trimmed.starts_with("#") || trimmed.is_empty() {
continue;
} else if trimmed.starts_with("[") && trimmed.ends_with("]") {
trimmed.remove(0);
trimmed.pop();
if let Some(ref section) = current_section {
infos.insert(section.header.clone(), section.body.clone());
}
current_section = Some(ConfigSection {
header: trimmed,
body: HashMap::new(),
});
} else {
let mut split = trimmed.split("=");
let key = match split.nth(0) {
Some(key) => key.trim().to_string(),
None => {
println!("cannot get key from line: {}", trimmed);
continue;
}
};
let value = match split.last() {
Some(value) => value.trim().to_string(),
None => {
println!("cannot get value from line: {}", trimmed);
continue;
}
};
if value.starts_with("[") && value.ends_with("]") {
let mut trimmed_value = value;
trimmed_value.remove(0);
trimmed_value.pop();
let value_split = trimmed_value.split(";");
let value_array = value_split.map(|v| v.trim().to_string()).collect();
if let Some(ref mut section) = current_section {
section.body.insert(key, Value::Array(value_array));
}
} else {
if let Some(ref mut section) = current_section {
section.body.insert(key, Value::Value(value));
}
}
}
}
}
// also push the last section
if let Some(section) = current_section {
infos.insert(section.header, section.body);
}
Ok(infos)
}
pub fn write_config(
file_name: &str,
sections: &Vec<(String, Vec<(String, Value)>)>,
) -> Result<(), String> {
let mut file = match File::create(file_name) {
Ok(file) => file,
Err(msg) => {
return Err(format!(
"error creating config file({}): {}",
file_name, msg
))
}
};
for (header, body) in sections {
let fmt_header = format!("[{}]\n", header);
if let Err(_) = file.write_all(fmt_header.as_bytes()) {
return Err(format!("failed writing section: {}", fmt_header));
}
for (key, value) in body {
let fmt_key_value = format!(
"{} = {}\n",
key,
match value {
Value::Value(val) => val.clone(),
Value::Array(array) => {
let mut array_value = "[".to_string();
for (i, val) in array.iter().enumerate() {
// if element is not the last one
if i != array.len() - 1 {
array_value = format!("{}{}, ", array_value, val);
} else {
array_value = format!("{}{}", array_value, val);
}
}
format!("{}]", array_value)
}
}
);
if let Err(_) = file.write_all(fmt_key_value.as_bytes()) {
return Err(format!("failed writing key value: {}", fmt_key_value));
}
}
if let Err(_) = file.write_all("\n".as_bytes()) {
return Err("failed writing new line".to_string());
}
}
Ok(())
}