storm_config/
builder.rs

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