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}