use crate::*;
use ::toml::*;
use std::env::*;
use std::fs;
use std::path::PathBuf;
pub struct Toml {
dir: Option<String>,
name: String,
}
struct TomlItem {
name: String,
value: Value,
}
impl PropertySource for TomlItem {
fn name(&self) -> String {
self.name.to_owned()
}
fn get_property(&self, name: &str) -> Option<Property> {
let mut v = &self.value;
lazy_static::lazy_static! {
static ref P: &'static [char] = &['.', '[', ']'];
}
for n in name.split(&P[..]) {
if n.is_empty() {
continue;
}
match v {
Value::Table(t) => v = t.get(n)?,
Value::Array(vs) => v = vs.get(n.parse::<usize>().ok()?)?,
_ => return None,
}
}
match v {
Value::String(vs) => Some(Property::Str(vs.to_owned())),
Value::Integer(vs) => Some(Property::Int(*vs)),
Value::Float(vs) => Some(Property::Float(*vs)),
Value::Boolean(vs) => Some(Property::Bool(*vs)),
Value::Datetime(vs) => Some(Property::Str(vs.to_string())),
_ => None,
}
}
fn is_empty(&self) -> bool {
match &self.value {
Value::Table(t) => t.is_empty(),
_ => false,
}
}
}
impl Toml {
pub fn new(dir: Option<String>, name: String) -> Self {
Self { dir, name }
}
pub fn build(&self) -> Vec<Option<Box<dyn PropertySource>>> {
let filename = format!("{}.toml", self.name);
let mut v = vec![];
if let Some(dir) = &self.dir {
v.push(Self::load(Some(PathBuf::from(dir)), &filename));
} else {
let current = current_dir().ok();
let mut home = var("HOME").ok().map(PathBuf::from);
if current == home {
home = None;
}
v.push(Self::load(current, &filename));
v.push(Self::load(home, &filename));
}
v
}
fn load(dir: Option<PathBuf>, file: &str) -> Option<Box<dyn PropertySource>> {
let mut dir = dir?;
dir.push(file);
Some(Box::new(TomlItem {
name: dir.display().to_string(),
value: from_str(&fs::read_to_string(dir).ok()?).ok()?,
}))
}
}