summaryrefslogtreecommitdiffstats
path: root/src/builder.rs
blob: 23090c68494afc75fde7ecec24d65d72a539131f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::{collections::HashMap, iter::IntoIterator};
use std::str::FromStr;

use crate::{
    config::Config, error, error::ConfigError, 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 alaways 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.
///
/// # Examples
///
/// ```rust
/// # use config::*;
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let mut builder = ConfigBuilder::default();
///
/// builder.set_default("default", "1")?;
/// builder.add_source(File::new("config/settings", FileFormat::Json));
/// builder.set_override("override", "1")?;
///
/// match builder.build() {
///     Ok(config) => {
///         // use your config
///     },
///     Err(e) => {
///         // 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, Default)]
pub struct ConfigBuilder {
    defaults: HashMap<Expression, Value>,
    overrides: HashMap<Expression, Value>,
    sources: Vec<Box<dyn Source + Send + Sync>>,
}

impl ConfigBuilder {
    /// Set a default `value` at `key`
    ///
    /// This value can be overwritten by any [`Source`] or override.
    ///
    /// # Errors
    ///
    /// Fails if `Expression::from_str(key)` fails.
    pub fn set_default<T>(&mut self, key: &str, value: T) -> error::Result<&mut ConfigBuilder>
    where
        T: Into<Value>,
    {
        self.defaults.insert(Expression::from_str(key)?, value.into());
        Ok(self)
    }

    /// 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.
    pub fn add_source<T>(&mut self, source: T) -> &mut Self
    where
        T: Source + Send + Sync + 'static,
    {
        self.sources.push(Box::new(source));
        self
    }

    /// Set an override
    ///
    /// This function sets an overwrite value. It will not be altered by any default or [`Source`]
    ///
    /// # Errors
    ///
    /// Fails if `Expression::from_str(key)` fails.
    pub fn set_override<T>(&mut self, key: &str, value: T) -> error::Result<&mut ConfigBuilder>
    where
        T: Into<Value>,
    {
        self.overrides.insert(Expression::from_str(key)?, value.into());
        Ok(self)
    }

    /// 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) -> error::Result<Config> {
        Self::build_internal(self.defaults, self.overrides, &self.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) -> 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 defaults.into_iter() {
            key.set(&mut cache, val);
        }

        // Add sources
        sources.collect_to(&mut cache)?;

        // Add overrides
        for (key, val) in overrides.into_iter() {
            key.set(&mut cache, val);
        }

        Ok(Config::new(cache))
    }
}