#![allow(clippy::missing_docs_in_private_items)]
use crate::error::{ConfigError, ConfigFields, Result};
#[derive(Debug, Clone)]
pub struct LoadBuilder {
app_name: String,
env_prefix: Option<String>,
use_files: bool,
use_env: bool,
}
impl LoadBuilder {
pub fn new(app_name: impl Into<String>) -> Self {
Self {
app_name: app_name.into(),
env_prefix: None,
use_files: true,
use_env: true,
}
}
#[must_use]
pub fn with_env_prefix(mut self, prefix: impl Into<String>) -> Self {
self.env_prefix = Some(prefix.into());
self
}
#[must_use]
pub const fn with_files(mut self, use_files: bool) -> Self {
self.use_files = use_files;
self
}
#[must_use]
pub const fn with_env(mut self, use_env: bool) -> Self {
self.use_env = use_env;
self
}
#[cfg(feature = "files")]
pub fn load<T>(&self) -> Result<T>
where
T: serde::de::DeserializeOwned + ConfigFields + Default,
{
let mut config: T = if self.use_files {
self.load_from_files().unwrap_or_default()
} else {
T::default()
};
if self.use_env {
config.load_from_env(self.env_prefix.as_deref())?;
}
Ok(config)
}
#[cfg(feature = "files")]
fn load_from_files<T>(&self) -> Result<T>
where
T: serde::de::DeserializeOwned,
{
use cfgmatic_files::load_first;
load_first::<T>(&self.app_name)
.map_err(ConfigError::File)?
.ok_or_else(|| ConfigError::not_found(format!("config files for {}", self.app_name)))
}
pub fn load_from_env<T>(&self) -> Result<T>
where
T: ConfigFields + Default,
{
let mut config = T::default();
config.load_from_env(self.env_prefix.as_deref())?;
Ok(config)
}
}
pub fn load_with(app_name: impl Into<String>) -> LoadBuilder {
LoadBuilder::new(app_name)
}