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}