summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRadosław Kot <rdkt13@gmail.com>2021-04-03 10:32:03 +0200
committerRadosław Kot <rdkt13@gmail.com>2021-04-03 10:32:03 +0200
commit95001bf4c3ff0ab64a72246a17040c50f1663575 (patch)
treeb8b82a2536ba3e364ac8d01933dc52f4198510a4
parent58709b048a6a7cdd687ec87d9c16b2db1f0c3059 (diff)
Cleanup, improve docs
-rw-r--r--src/builder.rs106
-rw-r--r--src/config.rs52
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>