| use std::iter::IntoIterator; |
| use std::str::FromStr; |
| |
| use crate::error::Result; |
| use crate::map::Map; |
| use crate::source::AsyncSource; |
| use crate::{config::Config, path::Expression, source::Source, value::Value}; |
| |
| /// A configuration builder |
| /// |
| /// It registers ordered sources of configuration to later build consistent [`Config`] from them. |
| /// Configuration sources it defines are defaults, [`Source`]s and overrides. |
| /// |
| /// Defaults are always loaded first and can be overwritten by any of two other sources. |
| /// Overrides are always loaded last, thus cannot be overridden. |
| /// Both can be only set explicitly key by key in code |
| /// using [`set_default`](Self::set_default) or [`set_override`](Self::set_override). |
| /// |
| /// An intermediate category, [`Source`], set groups of keys at once implicitly using data coming from external sources |
| /// like files, environment variables or others that one implements. Defining a [`Source`] is as simple as implementing |
| /// a trait for a struct. |
| /// |
| /// Adding sources, setting defaults and overrides does not invoke any I/O nor builds a config. |
| /// It happens on demand when [`build`](Self::build) (or its alternative) is called. |
| /// Therefore all errors, related to any of the [`Source`] will only show up then. |
| /// |
| /// # Sync and async builder |
| /// |
| /// [`ConfigBuilder`] uses type parameter to keep track of builder state. |
| /// |
| /// In [`DefaultState`] builder only supports [`Source`]s |
| /// |
| /// In [`AsyncState`] it supports both [`Source`]s and [`AsyncSource`]s at the price of building using `async fn`. |
| /// |
| /// # Examples |
| /// |
| /// ```rust |
| /// # use config::*; |
| /// # use std::error::Error; |
| /// # fn main() -> Result<(), Box<dyn Error>> { |
| /// let mut builder = Config::builder() |
| /// .set_default("default", "1")? |
| /// .add_source(File::new("config/settings", FileFormat::Json)) |
| /// // .add_async_source(...) |
| /// .set_override("override", "1")?; |
| /// |
| /// match builder.build() { |
| /// Ok(config) => { |
| /// // use your config |
| /// }, |
| /// Err(e) => { |
| /// // something went wrong |
| /// } |
| /// } |
| /// # Ok(()) |
| /// # } |
| /// ``` |
| /// |
| /// If any [`AsyncSource`] is used, the builder will transition to [`AsyncState`]. |
| /// In such case, it is required to _await_ calls to [`build`](Self::build) and its non-consuming sibling. |
| /// |
| /// Calls can be not chained as well |
| /// ```rust |
| /// # use std::error::Error; |
| /// # use config::*; |
| /// # fn main() -> Result<(), Box<dyn Error>> { |
| /// let mut builder = Config::builder(); |
| /// builder = builder.set_default("default", "1")?; |
| /// builder = builder.add_source(File::new("config/settings", FileFormat::Json)); |
| /// builder = builder.add_source(File::new("config/settings.prod", FileFormat::Json)); |
| /// builder = builder.set_override("override", "1")?; |
| /// # Ok(()) |
| /// # } |
| /// ``` |
| /// |
| /// Calling [`Config::builder`](Config::builder) yields builder in the default state. |
| /// If having an asynchronous state as the initial state is desired, _turbofish_ notation needs to be used. |
| /// ```rust |
| /// # use config::{*, builder::AsyncState}; |
| /// let mut builder = ConfigBuilder::<AsyncState>::default(); |
| /// ``` |
| /// |
| /// If for some reason acquiring builder in default state is required without calling [`Config::builder`](Config::builder) |
| /// it can also be achieved. |
| /// ```rust |
| /// # use config::{*, builder::DefaultState}; |
| /// let mut builder = ConfigBuilder::<DefaultState>::default(); |
| /// ``` |
| #[derive(Debug, Clone, Default)] |
| pub struct ConfigBuilder<St: BuilderState> { |
| defaults: Map<Expression, Value>, |
| overrides: Map<Expression, Value>, |
| state: St, |
| } |
| |
| /// Represents [`ConfigBuilder`] state. |
| pub trait BuilderState {} |
| |
| /// Represents data specific to builder in default, sychronous state, without support for async. |
| #[derive(Debug, Default, Clone)] |
| pub struct DefaultState { |
| sources: Vec<Box<dyn Source + Send + Sync>>, |
| } |
| |
| /// The asynchronous configuration builder. |
| /// |
| /// Similar to a [`ConfigBuilder`] it maintains a set of defaults, a set of sources, and overrides. |
| /// |
| /// Defaults do not override anything, sources override defaults, and overrides override anything else. |
| /// Within those three groups order of adding them at call site matters - entities added later take precedence. |
| /// |
| /// For more detailed description and examples see [`ConfigBuilder`]. |
| /// [`AsyncConfigBuilder`] is just an extension of it that takes async functions into account. |
| /// |
| /// To obtain a [`Config`] call [`build`](AsyncConfigBuilder::build) or [`build_cloned`](AsyncConfigBuilder::build_cloned) |
| /// |
| /// # Example |
| /// Since this library does not implement any [`AsyncSource`] an example in rustdocs cannot be given. |
| /// Detailed explanation about why such a source is not implemented is in [`AsyncSource`]'s documentation. |
| /// |
| /// Refer to [`ConfigBuilder`] for similar API sample usage or to the examples folder of the crate, where such a source is implemented. |
| #[derive(Debug, Clone, Default)] |
| pub struct AsyncConfigBuilder {} |
| |
| /// Represents data specific to builder in asychronous state, with support for async. |
| #[derive(Debug, Default, Clone)] |
| pub struct AsyncState { |
| sources: Vec<SourceType>, |
| } |
| |
| #[derive(Debug, Clone)] |
| enum SourceType { |
| Sync(Box<dyn Source + Send + Sync>), |
| Async(Box<dyn AsyncSource + Send + Sync>), |
| } |
| |
| impl BuilderState for DefaultState {} |
| impl BuilderState for AsyncState {} |
| |
| impl<St: BuilderState> ConfigBuilder<St> { |
| // operations allowed in any state |
| |
| /// Set a default `value` at `key` |
| /// |
| /// This value can be overwritten by any [`Source`], [`AsyncSource`] or override. |
| /// |
| /// # Errors |
| /// |
| /// Fails if `Expression::from_str(key)` fails. |
| 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) |
| } |
| |
| /// Set an override |
| /// |
| /// This function sets an overwrite value. It will not be altered by any default, [`Source`] nor [`AsyncSource`] |
| /// |
| /// # Errors |
| /// |
| /// Fails if `Expression::from_str(key)` fails. |
| 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) |
| } |
| |
| /// Sets an override if value is Some(_) |
| /// |
| /// This function sets an overwrite value if Some(_) is passed. If None is passed, this function does nothing. |
| /// It will not be altered by any default, [`Source`] nor [`AsyncSource`] |
| /// |
| /// # Errors |
| /// |
| /// Fails if `Expression::from_str(key)` fails. |
| 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> { |
| // operations allowed in sync state |
| |
| /// Registers new [`Source`] in this builder. |
| /// |
| /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use. |
| #[must_use] |
| pub fn add_source<T>(mut self, source: T) -> Self |
| where |
| T: Source + Send + Sync + 'static, |
| { |
| self.state.sources.push(Box::new(source)); |
| self |
| } |
| |
| /// Registers new [`AsyncSource`] in this builder and forces transition to [`AsyncState`]. |
| /// |
| /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use. |
| 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(|s| SourceType::Sync(s)) |
| .collect(), |
| }, |
| defaults: self.defaults, |
| overrides: self.overrides, |
| }; |
| |
| async_state.add_async_source(source) |
| } |
| |
| /// Reads all registered [`Source`]s. |
| /// |
| /// This is the method that invokes all I/O operations. |
| /// For a non consuming alternative see [`build_cloned`](Self::build_cloned) |
| /// |
| /// # Errors |
| /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons, |
| /// this method returns error. |
| pub fn build(self) -> Result<Config> { |
| Self::build_internal(self.defaults, self.overrides, &self.state.sources) |
| } |
| |
| /// Reads all registered [`Source`]s. |
| /// |
| /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse. |
| /// Internally it clones data to achieve it. |
| /// |
| /// # Errors |
| /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons, |
| /// this method returns error. |
| 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(); |
| |
| // Add defaults |
| for (key, val) in defaults { |
| key.set(&mut cache, val); |
| } |
| |
| // Add sources |
| sources.collect_to(&mut cache)?; |
| |
| // Add overrides |
| for (key, val) in overrides { |
| key.set(&mut cache, val); |
| } |
| |
| Ok(Config::new(cache)) |
| } |
| } |
| |
| impl ConfigBuilder<AsyncState> { |
| // operations allowed in async state |
| |
| /// Registers new [`Source`] in this builder. |
| /// |
| /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use. |
| #[must_use] |
| 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 |
| } |
| |
| /// Registers new [`AsyncSource`] in this builder. |
| /// |
| /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use. |
| #[must_use] |
| 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 |
| } |
| |
| /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides. |
| /// |
| /// This is the method that invokes all I/O operations. |
| /// For a non consuming alternative see [`build_cloned`](Self::build_cloned) |
| /// |
| /// # Errors |
| /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons, |
| /// this method returns error. |
| pub async fn build(self) -> Result<Config> { |
| Self::build_internal(self.defaults, self.overrides, &self.state.sources).await |
| } |
| |
| /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides. |
| /// |
| /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse. |
| /// Internally it clones data to achieve it. |
| /// |
| /// # Errors |
| /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons, |
| /// this method returns error. |
| 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(); |
| |
| // Add defaults |
| 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)?, |
| SourceType::Async(source) => source.collect_to(&mut cache).await?, |
| } |
| } |
| |
| // Add overrides |
| for (key, val) in overrides { |
| key.set(&mut cache, val); |
| } |
| |
| Ok(Config::new(cache)) |
| } |
| } |