#[cfg(test)]
mod tests;
use std::fmt;
use std::path::{Path, PathBuf};
use serde::Deserialize;
pub const DEFAULT: &str = include_str!("../assets/config.toml");
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub skills: Skills,
}
impl Config {
pub fn parse(text: &str, path: &Path) -> Result<Config, ConfigError> {
let config: Config =
toml::from_str(text).map_err(|source| ConfigError::new(path, source))?;
if config.skills.dir.is_empty() {
let source =
<toml::de::Error as serde::de::Error>::custom("`skills.dir` must not be empty");
return Err(ConfigError::new(path, source));
}
Ok(config)
}
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Skills {
pub dir: String,
}
#[derive(Debug)]
pub struct ConfigError {
path: PathBuf,
source: toml::de::Error,
}
impl ConfigError {
pub(crate) fn new(path: &Path, source: toml::de::Error) -> ConfigError {
ConfigError {
path: path.to_path_buf(),
source,
}
}
}
impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"the file at {} is invalid — fix it, or delete it and fairway will restore \
the defaults on the next run:\n{}",
self.path.display(),
self.source
)
}
}
impl std::error::Error for ConfigError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
}
}