use serde::Serialize;
use serde::de::DeserializeOwned;
#[cfg(not(target_family = "wasm"))]
use std::path::Path;
use thiserror::Error;
#[cfg(not(target_family = "wasm"))]
mod discovery;
#[cfg(not(target_family = "wasm"))]
pub use discovery::{find_config_files_from, merge_tables, read_toml_table, user_config_file};
#[derive(Error, Debug)]
pub enum ConfigError {
#[error("Error reading config file from {location}: {error}")]
Read { location: String, error: String },
#[error("Error parsing TOML config from {location}: {error}")]
Parse { location: String, error: String },
#[error("Error serializing config to TOML: {error}")]
Serialize { error: String },
#[error(
"Incompatible config version: the config targets rudof {config}, but this is rudof {rudof}. \
Upgrade rudof to at least {config}, or update the config's `version`."
)]
IncompatibleVersion { config: String, rudof: String },
}
pub trait TomlConfig: Sized + Default + Serialize + DeserializeOwned {
fn from_toml_str(s: &str) -> Result<Self, ConfigError> {
toml::from_str(s).map_err(|e| ConfigError::Parse {
location: "<string>".to_string(),
error: e.to_string(),
})
}
#[cfg(not(target_family = "wasm"))]
fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ConfigError> {
let path = path.as_ref();
let location = path.display().to_string();
let contents = std::fs::read_to_string(path).map_err(|e| {
let attempted = std::path::absolute(path)
.unwrap_or_else(|_| path.to_path_buf())
.display()
.to_string();
ConfigError::Read {
location: location.clone(),
error: format!("{e}. Path attempted: {attempted}"),
}
})?;
Self::from_toml_str(&contents).map_err(|e| match e {
ConfigError::Parse { error, .. } => ConfigError::Parse { location, error },
other => other,
})
}
fn to_toml_string(&self) -> Result<String, ConfigError> {
toml::to_string(self).map_err(|e| ConfigError::Serialize { error: e.to_string() })
}
}