use std::str::FromStr;
use crate::error::Result;
use crate::map::Map;
#[cfg(feature = "async")]
use crate::source::AsyncSource;
use crate::{config::Config, path::Expression, source::Source, value::Value};
#[derive(Debug, Clone, Default)]
#[must_use]
pub struct ConfigBuilder<St: BuilderState> {
defaults: Map<Expression, Value>,
overrides: Map<Expression, Value>,
state: St,
}
pub trait BuilderState {}
#[derive(Debug, Default, Clone)]
pub struct DefaultState {
sources: Vec<Box<dyn Source + Send + Sync>>,
}
#[derive(Debug, Default, Clone)]
pub struct AsyncState {
sources: Vec<SourceType>,
}
#[derive(Debug, Clone)]
enum SourceType {
Sync(Box<dyn Source + Send + Sync>),
#[cfg(feature = "async")]
Async(Box<dyn AsyncSource + Send + Sync>),
}
impl BuilderState for DefaultState {}
impl BuilderState for AsyncState {}
impl<St: BuilderState> ConfigBuilder<St> {
pub fn set_default<S, T>(mut self, key: S, value: T) -> Result<Self>
where
S: AsRef<str>,
T: Into<Value>,
{
self.defaults
.insert(Expression::from_str(key.as_ref())?, value.into());
Ok(self)
}
pub fn set_override<S, T>(mut self, key: S, value: T) -> Result<Self>
where
S: AsRef<str>,
T: Into<Value>,
{
self.overrides
.insert(Expression::from_str(key.as_ref())?, value.into());
Ok(self)
}
pub fn set_override_option<S, T>(mut self, key: S, value: Option<T>) -> Result<Self>
where
S: AsRef<str>,
T: Into<Value>,
{
if let Some(value) = value {
self.overrides
.insert(Expression::from_str(key.as_ref())?, value.into());
}
Ok(self)
}
}
impl ConfigBuilder<DefaultState> {
pub fn add_source<T>(mut self, source: T) -> Self
where
T: Source + Send + Sync + 'static,
{
self.state.sources.push(Box::new(source));
self
}
#[cfg(feature = "async")]
pub fn add_async_source<T>(self, source: T) -> ConfigBuilder<AsyncState>
where
T: AsyncSource + Send + Sync + 'static,
{
let async_state = ConfigBuilder {
state: AsyncState {
sources: self
.state
.sources
.into_iter()
.map(SourceType::Sync)
.collect(),
},
defaults: self.defaults,
overrides: self.overrides,
};
async_state.add_async_source(source)
}
pub fn build(self) -> Result<Config> {
Self::build_internal(self.defaults, self.overrides, &self.state.sources)
}
pub fn build_cloned(&self) -> Result<Config> {
Self::build_internal(
self.defaults.clone(),
self.overrides.clone(),
&self.state.sources,
)
}
fn build_internal(
defaults: Map<Expression, Value>,
overrides: Map<Expression, Value>,
sources: &[Box<dyn Source + Send + Sync>],
) -> Result<Config> {
let mut cache: Value = Map::<String, Value>::new().into();
for (key, val) in defaults {
key.set(&mut cache, val);
}
sources.collect_to(&mut cache)?;
for (key, val) in overrides {
key.set(&mut cache, val);
}
Ok(Config::new(cache))
}
}
impl ConfigBuilder<AsyncState> {
pub fn add_source<T>(mut self, source: T) -> Self
where
T: Source + Send + Sync + 'static,
{
self.state.sources.push(SourceType::Sync(Box::new(source)));
self
}
#[cfg(feature = "async")]
pub fn add_async_source<T>(mut self, source: T) -> Self
where
T: AsyncSource + Send + Sync + 'static,
{
self.state.sources.push(SourceType::Async(Box::new(source)));
self
}
pub async fn build(self) -> Result<Config> {
Self::build_internal(self.defaults, self.overrides, &self.state.sources).await
}
pub async fn build_cloned(&self) -> Result<Config> {
Self::build_internal(
self.defaults.clone(),
self.overrides.clone(),
&self.state.sources,
)
.await
}
async fn build_internal(
defaults: Map<Expression, Value>,
overrides: Map<Expression, Value>,
sources: &[SourceType],
) -> Result<Config> {
let mut cache: Value = Map::<String, Value>::new().into();
for (key, val) in defaults {
key.set(&mut cache, val);
}
for source in sources.iter() {
match source {
SourceType::Sync(source) => source.collect_to(&mut cache)?,
#[cfg(feature = "async")]
SourceType::Async(source) => source.collect_to(&mut cache).await?,
}
}
for (key, val) in overrides {
key.set(&mut cache, val);
}
Ok(Config::new(cache))
}
}