diff options
author | Radosław Kot <rdkt13@gmail.com> | 2021-04-03 10:32:03 +0200 |
---|---|---|
committer | Radosław Kot <rdkt13@gmail.com> | 2021-04-03 10:32:03 +0200 |
commit | 95001bf4c3ff0ab64a72246a17040c50f1663575 (patch) | |
tree | b8b82a2536ba3e364ac8d01933dc52f4198510a4 | |
parent | 58709b048a6a7cdd687ec87d9c16b2db1f0c3059 (diff) |
Cleanup, improve docs
-rw-r--r-- | src/builder.rs | 106 | ||||
-rw-r--r-- | src/config.rs | 52 |
2 files changed, 97 insertions, 61 deletions
diff --git a/src/builder.rs b/src/builder.rs index 68a9dac..dbf1aab 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,3 +1,8 @@ +use std::{ + collections::HashMap, + iter::IntoIterator +}; + use crate::{ config::Config, value::Value, @@ -6,7 +11,6 @@ use crate::{ error::ConfigError, path::Expression }; -use std::collections::HashMap; /** A configuration builder @@ -24,16 +28,20 @@ like files, environment variables or others that one implements. Defining a [`So 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) is called. +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. + +# Examples + ```rust # use config::*; - +# use std::error::Error; +# fn main() -> Result<(), Box<dyn Error>> { let mut builder = ConfigBuilder::default(); -builder.set_default("default", "1").expect("Key is valid"); +builder.set_default("default", "1")?; builder.add_source(File::new("config/settings", FileFormat::Json)); -builder.set_override("override", "1").expect("Key is valid"); +builder.set_override("override", "1")?; match builder.build() { Ok(config) => { @@ -43,9 +51,27 @@ match builder.build() { // something went wrong } } +# Ok(()) +# } +``` + +Calls can be chained as well +```rust +# use std::error::Error; +# use config::*; +# fn main() -> Result<(), Box<dyn Error>> { +let mut builder = ConfigBuilder::default(); + +builder + .set_default("default", "1")? + .add_source(File::new("config/settings", FileFormat::Json)) + .add_source(File::new("config/settings.prod", FileFormat::Json)) + .set_override("override", "1")?; +# Ok(()) +# } ``` */ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct ConfigBuilder { defaults: HashMap<Expression, Value>, overrides: HashMap<Expression, Value>, @@ -55,27 +81,12 @@ pub struct ConfigBuilder { impl ConfigBuilder { /** - Creates an empty `ConfigBuilder` without any configuration source registered. - - This is the [`Default`] implementation of `ConfigBuilder` - ```rust - # use config::ConfigBuilder; - let builder = ConfigBuilder::empty(); - ``` - */ - pub fn empty() -> Self { - ConfigBuilder { - defaults: HashMap::new(), - overrides: HashMap::new(), - sources: Vec::new(), - } - } - - /** Set a default `value` at `key` This value can be overwritten by any [`Source`] or override. + # Errors + Method can fail if `key` is not valid. */ pub fn set_default<T>(&mut self, key: &str, value: T) -> error::Result<&mut ConfigBuilder> @@ -103,6 +114,8 @@ impl ConfigBuilder This function sets an overwrite value. It will not be altered by any default or [`Source`] + # Errors + Method can fail if `key` is not valid. */ pub fn set_override<T>(&mut self, key: &str, value: T) -> error::Result<&mut ConfigBuilder> @@ -117,33 +130,50 @@ impl ConfigBuilder Reads all registered [`Source`]s. This is the method that invokes all I/O operations. - If any of them fail, be it technical reasons or related to inability to read data as `Config` for different reasons, + 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) -> error::Result<Config> { + Self::build_internal(self.defaults, self.overrides, &self.sources) + } + + /** + Reads all registered [`Source`]s. - It does not take ownership of `ConfigBuilder` to allow later reuse. Internally it clones data to achieve it. + 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(&self) -> error::Result<Config> { + pub fn build_cloned(&self) -> error::Result<Config> { + Self::build_internal(self.defaults.clone(), self.overrides.clone(), &self.sources) + } + + fn build_internal( + defaults: HashMap<Expression, Value>, + overrides: HashMap<Expression, Value>, + sources: &Vec<Box<dyn Source + Send + Sync>>, + ) -> error::Result<Config> { let mut cache: Value = HashMap::<String, Value>::new().into(); // Add defaults - for (key, val) in self.defaults.iter() { - key.set(&mut cache, val.clone()); + for (key, val) in defaults.into_iter() { + key.set(&mut cache, val); } // Add sources - self.sources.collect_to(&mut cache)?; + sources.collect_to(&mut cache)?; // Add overrides - for (key, val) in self.overrides.iter() { - key.set(&mut cache, val.clone()); + for (key, val) in overrides.into_iter() { + key.set(&mut cache, val); } - Ok(Config::new(cache)) - } -} - -impl Default for ConfigBuilder { - fn default() -> Self { - ConfigBuilder::empty() + Ok(Config::new(cache)) } }
\ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 02bef5f..8000f8e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -65,6 +65,11 @@ impl Config { } } + /// Creates new [`ConfigBuilder`] instance + pub fn builder() -> ConfigBuilder { + ConfigBuilder::default() + } + /// Merge in a configuration property source. #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] pub fn merge<T>(&mut self, source: T) -> Result<&mut Config> @@ -72,7 +77,18 @@ impl Config { T: 'static, T: Source + Send + Sync, { - self.push(source)?; + match self.kind { + ConfigKind::Mutable { + ref mut sources, .. + } => { + sources.push(Box::new(source)); + } + + ConfigKind::Frozen => { + return Err(ConfigError::Frozen); + } + } + self.refresh() } @@ -83,7 +99,18 @@ impl Config { T: 'static, T: Source + Send + Sync, { - self.push(source)?; + match self.kind { + ConfigKind::Mutable { + ref mut sources, .. + } => { + sources.push(Box::new(source)); + } + + ConfigKind::Frozen => { + return Err(ConfigError::Frozen); + } + } + self.refresh()?; Ok(self) } @@ -128,27 +155,6 @@ impl Config { Ok(self) } - /// Pushes new [`Source`] to Config unless it is frozen - #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] - pub(crate) fn push<T>(&mut self, source: T) -> Result<()> - where - T: 'static, - T: Source + Send + Sync - { - match self.kind { - ConfigKind::Mutable { - ref mut sources, .. - } => { - sources.push(Box::new(source)); - return Ok(()) - } - - ConfigKind::Frozen => { - return Err(ConfigError::Frozen); - } - } - } - /// Set a default `value` at `key` #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] pub fn set_default<T>(&mut self, key: &str, value: T) -> Result<&mut Config> |