config/
builder.rs

1use std::str::FromStr;
2
3use crate::error::Result;
4use crate::map::Map;
5#[cfg(feature = "async")]
6use crate::source::AsyncSource;
7use crate::{config::Config, path::Expression, source::Source, value::Value};
8
9/// A configuration builder
10///
11/// It registers ordered sources of configuration to later build consistent [`Config`] from them.
12/// Configuration sources it defines are defaults, [`Source`]s and overrides.
13///
14/// Defaults are always loaded first and can be overwritten by any of two other sources.
15/// Overrides are always loaded last, thus cannot be overridden.
16/// Both can be only set explicitly key by key in code
17/// using [`set_default`](Self::set_default) or [`set_override`](Self::set_override).
18///
19/// An intermediate category, [`Source`], set groups of keys at once implicitly using data coming from external sources
20/// like files, environment variables or others that one implements. Defining a [`Source`] is as simple as implementing
21/// a trait for a struct.
22///
23/// Adding sources, setting defaults and overrides does not invoke any I/O nor builds a config.
24/// It happens on demand when [`build`](Self::build) (or its alternative) is called.
25/// Therefore all errors, related to any of the [`Source`] will only show up then.
26///
27/// # Sync and async builder
28///
29/// [`ConfigBuilder`] uses type parameter to keep track of builder state.
30///
31/// In [`DefaultState`] builder only supports [`Source`]s
32///
33/// In [`AsyncState`] it supports both [`Source`]s and [`AsyncSource`]s at the price of building using `async fn`.
34///
35/// # Examples
36///
37/// ```rust
38/// # use config::*;
39/// # use std::error::Error;
40/// # fn main() -> Result<(), Box<dyn Error>> {
41/// # #[cfg(feature = "json")]
42/// # {
43/// let mut builder = Config::builder()
44///     .set_default("default", "1")?
45///     .add_source(File::new("config/settings", FileFormat::Json))
46/// //  .add_async_source(...)
47///     .set_override("override", "1")?;
48///
49/// match builder.build() {
50///     Ok(config) => {
51///         // use your config
52///     },
53///     Err(e) => {
54///         // something went wrong
55///     }
56/// }
57/// # }
58/// # Ok(())
59/// # }
60/// ```
61///
62/// If any [`AsyncSource`] is used, the builder will transition to [`AsyncState`].
63/// In such case, it is required to _await_ calls to [`build`](Self::build) and its non-consuming sibling.
64///
65/// Calls can be not chained as well
66/// ```rust
67/// # use std::error::Error;
68/// # use config::*;
69/// # fn main() -> Result<(), Box<dyn Error>> {
70/// # #[cfg(feature = "json")]
71/// # {
72/// let mut builder = Config::builder();
73/// builder = builder.set_default("default", "1")?;
74/// builder = builder.add_source(File::new("config/settings", FileFormat::Json));
75/// builder = builder.add_source(File::new("config/settings.prod", FileFormat::Json));
76/// builder = builder.set_override("override", "1")?;
77/// # }
78/// # Ok(())
79/// # }
80/// ```
81///
82/// Calling [`Config::builder`](Config::builder) yields builder in the default state.
83/// If having an asynchronous state as the initial state is desired, _turbofish_ notation needs to be used.
84/// ```rust
85/// # use config::{*, builder::AsyncState};
86/// let mut builder = ConfigBuilder::<AsyncState>::default();
87/// ```
88///
89/// If for some reason acquiring builder in default state is required without calling [`Config::builder`](Config::builder)
90/// it can also be achieved.
91/// ```rust
92/// # use config::{*, builder::DefaultState};
93/// let mut builder = ConfigBuilder::<DefaultState>::default();
94/// ```
95#[derive(Debug, Clone, Default)]
96#[must_use]
97pub struct ConfigBuilder<St: BuilderState> {
98    defaults: Map<Expression, Value>,
99    overrides: Map<Expression, Value>,
100    state: St,
101}
102
103/// Represents [`ConfigBuilder`] state.
104pub trait BuilderState {}
105
106/// Represents data specific to builder in default, synchronous state, without support for async.
107#[derive(Debug, Default, Clone)]
108pub struct DefaultState {
109    sources: Vec<Box<dyn Source + Send + Sync>>,
110}
111
112/// Represents data specific to builder in asynchronous state, with support for async.
113#[derive(Debug, Default, Clone)]
114pub struct AsyncState {
115    sources: Vec<SourceType>,
116}
117
118#[derive(Debug, Clone)]
119enum SourceType {
120    Sync(Box<dyn Source + Send + Sync>),
121    #[cfg(feature = "async")]
122    Async(Box<dyn AsyncSource + Send + Sync>),
123}
124
125impl BuilderState for DefaultState {}
126impl BuilderState for AsyncState {}
127
128/// Operations allowed in any state
129impl<St: BuilderState> ConfigBuilder<St> {
130    /// Set a default `value` at `key`
131    ///
132    /// This value can be overwritten by any [`Source`], [`AsyncSource`] or override.
133    ///
134    /// # Errors
135    ///
136    /// Fails if `Expression::from_str(key)` fails.
137    pub fn set_default<S, T>(mut self, key: S, value: T) -> Result<Self>
138    where
139        S: AsRef<str>,
140        T: Into<Value>,
141    {
142        self.defaults
143            .insert(Expression::from_str(key.as_ref())?, value.into());
144        Ok(self)
145    }
146
147    /// Set an override
148    ///
149    /// This function sets an overwrite value. It will not be altered by any default, [`Source`] nor [`AsyncSource`]
150    ///
151    /// # Errors
152    ///
153    /// Fails if `Expression::from_str(key)` fails.
154    pub fn set_override<S, T>(mut self, key: S, value: T) -> Result<Self>
155    where
156        S: AsRef<str>,
157        T: Into<Value>,
158    {
159        self.overrides
160            .insert(Expression::from_str(key.as_ref())?, value.into());
161        Ok(self)
162    }
163
164    /// Sets an override if value is Some(_)
165    ///
166    /// This function sets an overwrite value if Some(_) is passed. If None is passed, this function does nothing.
167    /// It will not be altered by any default, [`Source`] nor [`AsyncSource`]
168    ///
169    /// # Errors
170    ///
171    /// Fails if `Expression::from_str(key)` fails.
172    pub fn set_override_option<S, T>(mut self, key: S, value: Option<T>) -> Result<Self>
173    where
174        S: AsRef<str>,
175        T: Into<Value>,
176    {
177        if let Some(value) = value {
178            self.overrides
179                .insert(Expression::from_str(key.as_ref())?, value.into());
180        }
181        Ok(self)
182    }
183}
184
185/// Operations allowed in sync state
186impl ConfigBuilder<DefaultState> {
187    /// Registers new [`Source`] in this builder.
188    ///
189    /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
190    pub fn add_source<T>(mut self, source: T) -> Self
191    where
192        T: Source + Send + Sync + 'static,
193    {
194        self.state.sources.push(Box::new(source));
195        self
196    }
197
198    /// Registers new [`AsyncSource`] in this builder and forces transition to [`AsyncState`].
199    ///
200    /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
201    #[cfg(feature = "async")]
202    pub fn add_async_source<T>(self, source: T) -> ConfigBuilder<AsyncState>
203    where
204        T: AsyncSource + Send + Sync + 'static,
205    {
206        let async_state = ConfigBuilder {
207            state: AsyncState {
208                sources: self
209                    .state
210                    .sources
211                    .into_iter()
212                    .map(SourceType::Sync)
213                    .collect(),
214            },
215            defaults: self.defaults,
216            overrides: self.overrides,
217        };
218
219        async_state.add_async_source(source)
220    }
221
222    /// Reads all registered [`Source`]s.
223    ///
224    /// This is the method that invokes all I/O operations.
225    /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
226    ///
227    /// # Errors
228    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
229    /// this method returns error.
230    pub fn build(self) -> Result<Config> {
231        Self::build_internal(self.defaults, self.overrides, &self.state.sources)
232    }
233
234    /// Reads all registered [`Source`]s.
235    ///
236    /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
237    /// Internally it clones data to achieve it.
238    ///
239    /// # Errors
240    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
241    /// this method returns error.
242    pub fn build_cloned(&self) -> Result<Config> {
243        Self::build_internal(
244            self.defaults.clone(),
245            self.overrides.clone(),
246            &self.state.sources,
247        )
248    }
249
250    fn build_internal(
251        defaults: Map<Expression, Value>,
252        overrides: Map<Expression, Value>,
253        sources: &[Box<dyn Source + Send + Sync>],
254    ) -> Result<Config> {
255        let mut cache: Value = Map::<String, Value>::new().into();
256
257        // Add defaults
258        for (key, val) in defaults {
259            key.set(&mut cache, val);
260        }
261
262        // Add sources
263        sources.collect_to(&mut cache)?;
264
265        // Add overrides
266        for (key, val) in overrides {
267            key.set(&mut cache, val);
268        }
269
270        Ok(Config::new(cache))
271    }
272}
273
274/// Operations allowed in async state
275impl ConfigBuilder<AsyncState> {
276    /// Registers new [`Source`] in this builder.
277    ///
278    /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
279    pub fn add_source<T>(mut self, source: T) -> Self
280    where
281        T: Source + Send + Sync + 'static,
282    {
283        self.state.sources.push(SourceType::Sync(Box::new(source)));
284        self
285    }
286
287    /// Registers new [`AsyncSource`] in this builder.
288    ///
289    /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
290    #[cfg(feature = "async")]
291    pub fn add_async_source<T>(mut self, source: T) -> Self
292    where
293        T: AsyncSource + Send + Sync + 'static,
294    {
295        self.state.sources.push(SourceType::Async(Box::new(source)));
296        self
297    }
298
299    /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
300    ///
301    /// This is the method that invokes all I/O operations.
302    /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
303    ///
304    /// # Errors
305    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
306    /// this method returns error.
307    pub async fn build(self) -> Result<Config> {
308        Self::build_internal(self.defaults, self.overrides, &self.state.sources).await
309    }
310
311    /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
312    ///
313    /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
314    /// Internally it clones data to achieve it.
315    ///
316    /// # Errors
317    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
318    /// this method returns error.
319    pub async fn build_cloned(&self) -> Result<Config> {
320        Self::build_internal(
321            self.defaults.clone(),
322            self.overrides.clone(),
323            &self.state.sources,
324        )
325        .await
326    }
327
328    async fn build_internal(
329        defaults: Map<Expression, Value>,
330        overrides: Map<Expression, Value>,
331        sources: &[SourceType],
332    ) -> Result<Config> {
333        let mut cache: Value = Map::<String, Value>::new().into();
334
335        // Add defaults
336        for (key, val) in defaults {
337            key.set(&mut cache, val);
338        }
339
340        for source in sources.iter() {
341            match source {
342                SourceType::Sync(source) => source.collect_to(&mut cache)?,
343                #[cfg(feature = "async")]
344                SourceType::Async(source) => source.collect_to(&mut cache).await?,
345            }
346        }
347
348        // Add overrides
349        for (key, val) in overrides {
350            key.set(&mut cache, val);
351        }
352
353        Ok(Config::new(cache))
354    }
355}