|
| 1 | +use std::str::FromStr; |
| 2 | +use std::{collections::HashMap, iter::IntoIterator}; |
| 3 | + |
| 4 | +use crate::{config::Config, error, path::Expression, source::Source, value::Value}; |
| 5 | + |
| 6 | +/// A configuration builder |
| 7 | +/// |
| 8 | +/// It registers ordered sources of configuration to later build consistent [`Config`] from them. |
| 9 | +/// Configuration sources it defines are defaults, [`Source`]s and overrides. |
| 10 | +/// |
| 11 | +/// Defaults are alaways loaded first and can be overwritten by any of two other sources. |
| 12 | +/// Overrides are always loaded last, thus cannot be overridden. |
| 13 | +/// Both can be only set explicitly key by key in code |
| 14 | +/// using [`set_default`](Self::set_default) or [`set_override`](Self::set_override). |
| 15 | +/// |
| 16 | +/// An intermediate category, [`Source`], set groups of keys at once implicitly using data coming from external sources |
| 17 | +/// like files, environment variables or others that one implements. Defining a [`Source`] is as simple as implementing |
| 18 | +/// a trait for a struct. |
| 19 | +/// |
| 20 | +/// Adding sources, setting defaults and overrides does not invoke any I/O nor builds a config. |
| 21 | +/// It happens on demand when [`build`](Self::build) (or its alternative) is called. |
| 22 | +/// Therefore all errors, related to any of the [`Source`] will only show up then. |
| 23 | +/// |
| 24 | +/// # Examples |
| 25 | +/// |
| 26 | +/// ```rust |
| 27 | +/// # use config::*; |
| 28 | +/// # use std::error::Error; |
| 29 | +/// # fn main() -> Result<(), Box<dyn Error>> { |
| 30 | +/// let mut builder = ConfigBuilder::default() |
| 31 | +/// .set_default("default", "1")? |
| 32 | +/// .add_source(File::new("config/settings", FileFormat::Json)) |
| 33 | +/// .set_override("override", "1")?; |
| 34 | +/// |
| 35 | +/// match builder.build() { |
| 36 | +/// Ok(config) => { |
| 37 | +/// // use your config |
| 38 | +/// }, |
| 39 | +/// Err(e) => { |
| 40 | +/// // something went wrong |
| 41 | +/// } |
| 42 | +/// } |
| 43 | +/// # Ok(()) |
| 44 | +/// # } |
| 45 | +/// ``` |
| 46 | +/// |
| 47 | +/// Calls can be not chained as well |
| 48 | +/// ```rust |
| 49 | +/// # use std::error::Error; |
| 50 | +/// # use config::*; |
| 51 | +/// # fn main() -> Result<(), Box<dyn Error>> { |
| 52 | +/// let mut builder = ConfigBuilder::default(); |
| 53 | +/// builder = builder.set_default("default", "1")?; |
| 54 | +/// builder = builder.add_source(File::new("config/settings", FileFormat::Json)); |
| 55 | +/// builder = builder.add_source(File::new("config/settings.prod", FileFormat::Json)); |
| 56 | +/// builder = builder.set_override("override", "1")?; |
| 57 | +/// # Ok(()) |
| 58 | +/// # } |
| 59 | +/// ``` |
| 60 | +#[derive(Debug, Clone, Default)] |
| 61 | +pub struct ConfigBuilder { |
| 62 | + defaults: HashMap<Expression, Value>, |
| 63 | + overrides: HashMap<Expression, Value>, |
| 64 | + sources: Vec<Box<dyn Source + Send + Sync>>, |
| 65 | +} |
| 66 | + |
| 67 | +impl ConfigBuilder { |
| 68 | + /// Set a default `value` at `key` |
| 69 | + /// |
| 70 | + /// This value can be overwritten by any [`Source`] or override. |
| 71 | + /// |
| 72 | + /// # Errors |
| 73 | + /// |
| 74 | + /// Fails if `Expression::from_str(key)` fails. |
| 75 | + pub fn set_default<S, T>(mut self, key: S, value: T) -> error::Result<ConfigBuilder> |
| 76 | + where |
| 77 | + S: AsRef<str>, |
| 78 | + T: Into<Value>, |
| 79 | + { |
| 80 | + self.defaults |
| 81 | + .insert(Expression::from_str(key.as_ref())?, value.into()); |
| 82 | + Ok(self) |
| 83 | + } |
| 84 | + |
| 85 | + /// Registers new [`Source`] in this builder. |
| 86 | + /// |
| 87 | + /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use. |
| 88 | + pub fn add_source<T>(mut self, source: T) -> Self |
| 89 | + where |
| 90 | + T: Source + Send + Sync + 'static, |
| 91 | + { |
| 92 | + self.sources.push(Box::new(source)); |
| 93 | + self |
| 94 | + } |
| 95 | + |
| 96 | + /// Set an override |
| 97 | + /// |
| 98 | + /// This function sets an overwrite value. It will not be altered by any default or [`Source`] |
| 99 | + /// |
| 100 | + /// # Errors |
| 101 | + /// |
| 102 | + /// Fails if `Expression::from_str(key)` fails. |
| 103 | + pub fn set_override<S, T>(mut self, key: S, value: T) -> error::Result<ConfigBuilder> |
| 104 | + where |
| 105 | + S: AsRef<str>, |
| 106 | + T: Into<Value>, |
| 107 | + { |
| 108 | + self.overrides |
| 109 | + .insert(Expression::from_str(key.as_ref())?, value.into()); |
| 110 | + Ok(self) |
| 111 | + } |
| 112 | + |
| 113 | + /// Reads all registered [`Source`]s. |
| 114 | + /// |
| 115 | + /// This is the method that invokes all I/O operations. |
| 116 | + /// For a non consuming alternative see [`build_cloned`](Self::build_cloned) |
| 117 | + /// |
| 118 | + /// # Errors |
| 119 | + /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons, |
| 120 | + /// this method returns error. |
| 121 | + pub fn build(self) -> error::Result<Config> { |
| 122 | + Self::build_internal(self.defaults, self.overrides, &self.sources) |
| 123 | + } |
| 124 | + |
| 125 | + /// Reads all registered [`Source`]s. |
| 126 | + /// |
| 127 | + /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse. |
| 128 | + /// Internally it clones data to achieve it. |
| 129 | + /// |
| 130 | + /// # Errors |
| 131 | + /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons, |
| 132 | + /// this method returns error. |
| 133 | + pub fn build_cloned(&self) -> error::Result<Config> { |
| 134 | + Self::build_internal(self.defaults.clone(), self.overrides.clone(), &self.sources) |
| 135 | + } |
| 136 | + |
| 137 | + fn build_internal( |
| 138 | + defaults: HashMap<Expression, Value>, |
| 139 | + overrides: HashMap<Expression, Value>, |
| 140 | + sources: &[Box<dyn Source + Send + Sync>], |
| 141 | + ) -> error::Result<Config> { |
| 142 | + let mut cache: Value = HashMap::<String, Value>::new().into(); |
| 143 | + |
| 144 | + // Add defaults |
| 145 | + for (key, val) in defaults.into_iter() { |
| 146 | + key.set(&mut cache, val); |
| 147 | + } |
| 148 | + |
| 149 | + // Add sources |
| 150 | + sources.collect_to(&mut cache)?; |
| 151 | + |
| 152 | + // Add overrides |
| 153 | + for (key, val) in overrides.into_iter() { |
| 154 | + key.set(&mut cache, val); |
| 155 | + } |
| 156 | + |
| 157 | + Ok(Config::new(cache)) |
| 158 | + } |
| 159 | +} |
0 commit comments