use std::path::Path;
use hashbrown::{HashMap, HashSet};
use serde_derive::{Serialize, Deserialize};
use serde_json::Value;
use toml;
use crate::types::TypeDesc;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Visibility {
None,
User,
Advanced,
Expert,
}
impl Default for Visibility {
fn default() -> Self { Visibility::User }
}
#[derive(Deserialize, Debug)]
pub struct ServerConfig {
#[serde(skip)] pub equipment_id: String,
pub description: String,
pub modules: HashMap<String, ModuleConfig>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct ModuleConfig {
pub class: String,
pub description: String,
pub group: Option<String>,
#[serde(default)]
pub parameters: HashMap<String, Value>,
#[serde(default)]
pub visibility: Visibility,
}
pub fn load_config(filename: impl AsRef<Path>) -> Result<ServerConfig, String> {
let data = std::fs::read(&filename).map_err(|e| e.to_string())?;
let mut obj: ServerConfig = toml::from_slice(&data).map_err(|e| e.to_string())?;
obj.equipment_id = filename.as_ref()
.file_stem()
.map_or("unknown".into(), |s| s.to_string_lossy().into_owned());
let mut lc_names = HashSet::new();
let mut lc_groups = HashSet::new();
for modcfg in obj.modules.values() {
if let Some(group) = modcfg.group.as_ref() {
lc_groups.insert(group.to_string());
}
}
for name in obj.modules.keys() {
let lc_name = name.to_lowercase();
if lc_groups.contains(&lc_name) || !lc_names.insert(lc_name) {
return Err(format!("module name {} is not unique amoung modules and groups", name))
}
}
Ok(obj)
}
impl ModuleConfig {
pub fn extract_param<T: TypeDesc>(&self, param: &str, td: &T) -> Option<T::Repr> {
self.parameters.get(param).and_then(|v| td.from_json(v).ok())
}
}