storm_config/
builder.rs

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