okcodes_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/// let mut builder = Config::builder()
42///     .set_default("default", "1")?
43///     .add_source(File::new("config/settings", FileFormat::Json))
44/// //  .add_async_source(...)
45///     .set_override("override", "1")?;
46///
47/// match builder.build() {
48///     Ok(config) => {
49///         // use your config
50///     },
51///     Err(e) => {
52///         // something went wrong
53///     }
54/// }
55/// # Ok(())
56/// # }
57/// ```
58///
59/// If any [`AsyncSource`] is used, the builder will transition to [`AsyncState`].
60/// In such case, it is required to _await_ calls to [`build`](Self::build) and its non-consuming sibling.
61///
62/// Calls can be not chained as well
63/// ```rust
64/// # use std::error::Error;
65/// # use config::*;
66/// # fn main() -> Result<(), Box<dyn Error>> {
67/// let mut builder = Config::builder();
68/// builder = builder.set_default("default", "1")?;
69/// builder = builder.add_source(File::new("config/settings", FileFormat::Json));
70/// builder = builder.add_source(File::new("config/settings.prod", FileFormat::Json));
71/// builder = builder.set_override("override", "1")?;
72/// # Ok(())
73/// # }
74/// ```
75///
76/// Calling [`Config::builder`](Config::builder) yields builder in the default state.
77/// If having an asynchronous state as the initial state is desired, _turbofish_ notation needs to be used.
78/// ```rust
79/// # use config::{*, builder::AsyncState};
80/// let mut builder = ConfigBuilder::<AsyncState>::default();
81/// ```
82///
83/// If for some reason acquiring builder in default state is required without calling [`Config::builder`](Config::builder)
84/// it can also be achieved.
85/// ```rust
86/// # use config::{*, builder::DefaultState};
87/// let mut builder = ConfigBuilder::<DefaultState>::default();
88/// ```
89#[derive(Debug, Clone, Default)]
90#[must_use]
91pub struct ConfigBuilder<St: BuilderState> {
92    defaults: Map<Expression, Value>,
93    overrides: Map<Expression, Value>,
94    state: St,
95}
96
97/// Represents [`ConfigBuilder`] state.
98pub trait BuilderState {}
99
100/// Represents data specific to builder in default, sychronous state, without support for async.
101#[derive(Debug, Default, Clone)]
102pub struct DefaultState {
103    sources: Vec<Box<dyn Source + Send + Sync>>,
104}
105
106// Dummy useless struct
107//
108// This struct exists only to avoid the semver break
109// which would be implied by removing it.
110//
111// This struct cannot be used for anything useful.
112// (Nor can it be extended without a semver break, either.)
113//
114// In a future release, we should have
115//    type AsyncConfigBuilder = ConfigBuilder<AsyncState>;
116#[deprecated = "AsyncConfigBuilder is useless.  Use ConfigBuilder<AsyncState>"]
117#[doc(hidden)]
118#[derive(Debug, Clone, Default)]
119pub struct AsyncConfigBuilder {}
120
121/// Represents data specific to builder in asychronous state, with support for async.
122#[derive(Debug, Default, Clone)]
123pub struct AsyncState {
124    sources: Vec<SourceType>,
125}
126
127#[derive(Debug, Clone)]
128enum SourceType {
129    Sync(Box<dyn Source + Send + Sync>),
130    #[cfg(feature = "async")]
131    Async(Box<dyn AsyncSource + Send + Sync>),
132}
133
134impl BuilderState for DefaultState {}
135impl BuilderState for AsyncState {}
136
137impl<St: BuilderState> ConfigBuilder<St> {
138    // operations allowed in any state
139
140    /// Set a default `value` at `key`
141    ///
142    /// This value can be overwritten by any [`Source`], [`AsyncSource`] or override.
143    ///
144    /// # Errors
145    ///
146    /// Fails if `Expression::from_str(key)` fails.
147    pub fn set_default<S, T>(mut self, key: S, value: T) -> Result<Self>
148    where
149        S: AsRef<str>,
150        T: Into<Value>,
151    {
152        self.defaults
153            .insert(Expression::from_str(key.as_ref())?, value.into());
154        Ok(self)
155    }
156
157    /// Set an override
158    ///
159    /// This function sets an overwrite value. It will not be altered by any default, [`Source`] nor [`AsyncSource`]
160    ///
161    /// # Errors
162    ///
163    /// Fails if `Expression::from_str(key)` fails.
164    pub fn set_override<S, T>(mut self, key: S, value: T) -> Result<Self>
165    where
166        S: AsRef<str>,
167        T: Into<Value>,
168    {
169        self.overrides
170            .insert(Expression::from_str(key.as_ref())?, value.into());
171        Ok(self)
172    }
173
174    /// Sets an override if value is Some(_)
175    ///
176    /// This function sets an overwrite value if Some(_) is passed. If None is passed, this function does nothing.
177    /// It will not be altered by any default, [`Source`] nor [`AsyncSource`]
178    ///
179    /// # Errors
180    ///
181    /// Fails if `Expression::from_str(key)` fails.
182    pub fn set_override_option<S, T>(mut self, key: S, value: Option<T>) -> Result<Self>
183    where
184        S: AsRef<str>,
185        T: Into<Value>,
186    {
187        if let Some(value) = value {
188            self.overrides
189                .insert(Expression::from_str(key.as_ref())?, value.into());
190        }
191        Ok(self)
192    }
193}
194
195impl ConfigBuilder<DefaultState> {
196    // operations allowed in sync state
197
198    /// Registers new [`Source`] in this builder.
199    ///
200    /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
201    pub fn add_source<T>(mut self, source: T) -> Self
202    where
203        T: Source + Send + Sync + 'static,
204    {
205        self.state.sources.push(Box::new(source));
206        self
207    }
208
209    /// Registers new [`AsyncSource`] in this builder and forces transition to [`AsyncState`].
210    ///
211    /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
212    #[cfg(feature = "async")]
213    pub fn add_async_source<T>(self, source: T) -> ConfigBuilder<AsyncState>
214    where
215        T: AsyncSource + Send + Sync + 'static,
216    {
217        let async_state = ConfigBuilder {
218            state: AsyncState {
219                sources: self
220                    .state
221                    .sources
222                    .into_iter()
223                    .map(SourceType::Sync)
224                    .collect(),
225            },
226            defaults: self.defaults,
227            overrides: self.overrides,
228        };
229
230        async_state.add_async_source(source)
231    }
232
233    /// Reads all registered [`Source`]s.
234    ///
235    /// This is the method that invokes all I/O operations.
236    /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
237    ///
238    /// # Errors
239    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
240    /// this method returns error.
241    pub fn build(self) -> Result<Config> {
242        Self::build_internal(self.defaults, self.overrides, &self.state.sources)
243    }
244
245    /// Reads all registered [`Source`]s.
246    ///
247    /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
248    /// Internally it clones data to achieve it.
249    ///
250    /// # Errors
251    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
252    /// this method returns error.
253    pub fn build_cloned(&self) -> Result<Config> {
254        Self::build_internal(
255            self.defaults.clone(),
256            self.overrides.clone(),
257            &self.state.sources,
258        )
259    }
260
261    fn build_internal(
262        defaults: Map<Expression, Value>,
263        overrides: Map<Expression, Value>,
264        sources: &[Box<dyn Source + Send + Sync>],
265    ) -> Result<Config> {
266        let mut cache: Value = Map::<String, Value>::new().into();
267
268        // Add defaults
269        for (key, val) in defaults {
270            key.set(&mut cache, val);
271        }
272
273        // Add sources
274        sources.collect_to(&mut cache)?;
275
276        // Add overrides
277        for (key, val) in overrides {
278            key.set(&mut cache, val);
279        }
280
281        Ok(Config::new(cache))
282    }
283}
284
285impl ConfigBuilder<AsyncState> {
286    // operations allowed in async state
287
288    /// Registers new [`Source`] in this builder.
289    ///
290    /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
291    pub fn add_source<T>(mut self, source: T) -> Self
292    where
293        T: Source + Send + Sync + 'static,
294    {
295        self.state.sources.push(SourceType::Sync(Box::new(source)));
296        self
297    }
298
299    /// Registers new [`AsyncSource`] in this builder.
300    ///
301    /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
302    #[cfg(feature = "async")]
303    pub fn add_async_source<T>(mut self, source: T) -> Self
304    where
305        T: AsyncSource + Send + Sync + 'static,
306    {
307        self.state.sources.push(SourceType::Async(Box::new(source)));
308        self
309    }
310
311    /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
312    ///
313    /// This is the method that invokes all I/O operations.
314    /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
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(self) -> Result<Config> {
320        Self::build_internal(self.defaults, self.overrides, &self.state.sources).await
321    }
322
323    /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
324    ///
325    /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
326    /// Internally it clones data to achieve it.
327    ///
328    /// # Errors
329    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
330    /// this method returns error.
331    pub async fn build_cloned(&self) -> Result<Config> {
332        Self::build_internal(
333            self.defaults.clone(),
334            self.overrides.clone(),
335            &self.state.sources,
336        )
337        .await
338    }
339
340    async fn build_internal(
341        defaults: Map<Expression, Value>,
342        overrides: Map<Expression, Value>,
343        sources: &[SourceType],
344    ) -> Result<Config> {
345        let mut cache: Value = Map::<String, Value>::new().into();
346
347        // Add defaults
348        for (key, val) in defaults {
349            key.set(&mut cache, val);
350        }
351
352        for source in sources.iter() {
353            match source {
354                SourceType::Sync(source) => source.collect_to(&mut cache)?,
355                #[cfg(feature = "async")]
356                SourceType::Async(source) => source.collect_to(&mut cache).await?,
357            }
358        }
359
360        // Add overrides
361        for (key, val) in overrides {
362            key.set(&mut cache, val);
363        }
364
365        Ok(Config::new(cache))
366    }
367}