@@ -2,6 +2,7 @@ use std::str::FromStr;
2
2
use std:: { collections:: HashMap , iter:: IntoIterator } ;
3
3
4
4
use crate :: error:: Result ;
5
+ use crate :: source:: AsyncSource ;
5
6
use crate :: { config:: Config , path:: Expression , source:: Source , value:: Value } ;
6
7
7
8
/// A configuration builder
@@ -22,15 +23,24 @@ use crate::{config::Config, path::Expression, source::Source, value::Value};
22
23
/// It happens on demand when [`build`](Self::build) (or its alternative) is called.
23
24
/// Therefore all errors, related to any of the [`Source`] will only show up then.
24
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
+ ///
25
34
/// # Examples
26
35
///
27
36
/// ```rust
28
37
/// # use config::*;
29
38
/// # use std::error::Error;
30
39
/// # fn main() -> Result<(), Box<dyn Error>> {
31
- /// let mut builder = ConfigBuilder::default ()
40
+ /// let mut builder = Config::builder ()
32
41
/// .set_default("default", "1")?
33
42
/// .add_source(File::new("config/settings", FileFormat::Json))
43
+ /// // .add_async_source(...)
34
44
/// .set_override("override", "1")?;
35
45
///
36
46
/// match builder.build() {
@@ -45,35 +55,102 @@ use crate::{config::Config, path::Expression, source::Source, value::Value};
45
55
/// # }
46
56
/// ```
47
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
+ ///
48
61
/// Calls can be not chained as well
49
62
/// ```rust
50
63
/// # use std::error::Error;
51
64
/// # use config::*;
52
65
/// # fn main() -> Result<(), Box<dyn Error>> {
53
- /// let mut builder = ConfigBuilder::default ();
66
+ /// let mut builder = Config::builder ();
54
67
/// builder = builder.set_default("default", "1")?;
55
68
/// builder = builder.add_source(File::new("config/settings", FileFormat::Json));
56
69
/// builder = builder.add_source(File::new("config/settings.prod", FileFormat::Json));
57
70
/// builder = builder.set_override("override", "1")?;
58
71
/// # Ok(())
59
72
/// # }
60
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 config::{*, 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 config::{*, builder::DefaultState};
86
+ /// let mut builder = ConfigBuilder::<DefaultState>::default();
87
+ /// ```
61
88
#[ derive( Debug , Clone , Default ) ]
62
- pub struct ConfigBuilder {
89
+ pub struct ConfigBuilder < St : BuilderState > {
63
90
defaults : HashMap < Expression , Value > ,
64
91
overrides : HashMap < Expression , Value > ,
92
+ state : St ,
93
+ }
94
+
95
+ /// Represents [`ConfigBuilder`] state.
96
+ pub trait BuilderState { }
97
+
98
+ /// Represents data specific to builder in default, sychronous state, without support for async.
99
+ #[ derive( Debug , Default ) ]
100
+ pub struct DefaultState {
65
101
sources : Vec < Box < dyn Source + Send + Sync > > ,
66
102
}
67
103
68
- impl ConfigBuilder {
104
+ /// The asynchronous configuration builder.
105
+ ///
106
+ /// Similar to a [`ConfigBuilder`] it maintains a set of defaults, a set of sources, and overrides.
107
+ ///
108
+ /// Defaults do not override anything, sources override defaults, and overrides override anything else.
109
+ /// Within those three groups order of adding them at call site matters - entities added later take precedence.
110
+ ///
111
+ /// For more detailed description and examples see [`ConfigBuilder`].
112
+ /// [`AsyncConfigBuilder`] is just an extension of it that takes async functions into account.
113
+ ///
114
+ /// To obtain a [`Config`] call [`build`](AsyncConfigBuilder::build) or [`build_cloned`](AsyncConfigBuilder::build_cloned)
115
+ ///
116
+ /// # Example
117
+ /// Since this library does not implement any [`AsyncSource`] an example in rustdocs cannot be given.
118
+ /// Detailed explanation about why such a source is not implemented is in [`AsyncSource`]'s documentation.
119
+ ///
120
+ /// Refer to [`ConfigBuilder`] for similar API sample usage or to the examples folder of the crate, where such a source is implemented.
121
+ #[ derive( Debug , Clone , Default ) ]
122
+ pub struct AsyncConfigBuilder {
123
+ defaults : HashMap < Expression , Value > ,
124
+ overrides : HashMap < Expression , Value > ,
125
+ sources : Vec < SourceType > ,
126
+ }
127
+
128
+ /// Represents data specific to builder in asychronous state, with support for async.
129
+ #[ derive( Debug , Default ) ]
130
+ pub struct AsyncState {
131
+ sources : Vec < SourceType > ,
132
+ }
133
+
134
+ #[ derive( Debug , Clone ) ]
135
+ enum SourceType {
136
+ Sync ( Box < dyn Source + Send + Sync > ) ,
137
+ Async ( Box < dyn AsyncSource + Send + Sync > ) ,
138
+ }
139
+
140
+ impl BuilderState for DefaultState { }
141
+ impl BuilderState for AsyncState { }
142
+
143
+ impl < St : BuilderState > ConfigBuilder < St > {
144
+ // operations allowed in any state
145
+
69
146
/// Set a default `value` at `key`
70
147
///
71
- /// This value can be overwritten by any [`Source`] or override.
148
+ /// This value can be overwritten by any [`Source`], [`AsyncSource`] or override.
72
149
///
73
150
/// # Errors
74
151
///
75
152
/// Fails if `Expression::from_str(key)` fails.
76
- pub fn set_default < S , T > ( mut self , key : S , value : T ) -> Result < ConfigBuilder >
153
+ pub fn set_default < S , T > ( mut self , key : S , value : T ) -> Result < ConfigBuilder < St > >
77
154
where
78
155
S : AsRef < str > ,
79
156
T : Into < Value > ,
@@ -83,25 +160,14 @@ impl ConfigBuilder {
83
160
Ok ( self )
84
161
}
85
162
86
- /// Registers new [`Source`] in this builder.
87
- ///
88
- /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
89
- pub fn add_source < T > ( mut self , source : T ) -> Self
90
- where
91
- T : Source + Send + Sync + ' static ,
92
- {
93
- self . sources . push ( Box :: new ( source) ) ;
94
- self
95
- }
96
-
97
163
/// Set an override
98
164
///
99
- /// This function sets an overwrite value. It will not be altered by any default or [`Source`]
165
+ /// This function sets an overwrite value. It will not be altered by any default, [`Source`] nor [`AsyncSource `]
100
166
///
101
167
/// # Errors
102
168
///
103
169
/// Fails if `Expression::from_str(key)` fails.
104
- pub fn set_override < S , T > ( mut self , key : S , value : T ) -> Result < ConfigBuilder >
170
+ pub fn set_override < S , T > ( mut self , key : S , value : T ) -> Result < ConfigBuilder < St > >
105
171
where
106
172
S : AsRef < str > ,
107
173
T : Into < Value > ,
@@ -110,6 +176,44 @@ impl ConfigBuilder {
110
176
. insert ( Expression :: from_str ( key. as_ref ( ) ) ?, value. into ( ) ) ;
111
177
Ok ( self )
112
178
}
179
+ }
180
+
181
+ impl ConfigBuilder < DefaultState > {
182
+ // operations allowed in sync state
183
+
184
+ /// Registers new [`Source`] in this builder.
185
+ ///
186
+ /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
187
+ pub fn add_source < T > ( mut self , source : T ) -> Self
188
+ where
189
+ T : Source + Send + Sync + ' static ,
190
+ {
191
+ self . state . sources . push ( Box :: new ( source) ) ;
192
+ self
193
+ }
194
+
195
+ /// Registers new [`AsyncSource`] in this builder and forces transition to [`AsyncState`].
196
+ ///
197
+ /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
198
+ pub fn add_async_source < T > ( self , source : T ) -> ConfigBuilder < AsyncState >
199
+ where
200
+ T : AsyncSource + Send + Sync + ' static ,
201
+ {
202
+ let async_state = ConfigBuilder {
203
+ state : AsyncState {
204
+ sources : self
205
+ . state
206
+ . sources
207
+ . into_iter ( )
208
+ . map ( |s| SourceType :: Sync ( s) )
209
+ . collect ( ) ,
210
+ } ,
211
+ defaults : self . defaults ,
212
+ overrides : self . overrides ,
213
+ } ;
214
+
215
+ async_state. add_async_source ( source)
216
+ }
113
217
114
218
/// Reads all registered [`Source`]s.
115
219
///
@@ -120,7 +224,7 @@ impl ConfigBuilder {
120
224
/// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
121
225
/// this method returns error.
122
226
pub fn build ( self ) -> Result < Config > {
123
- Self :: build_internal ( self . defaults , self . overrides , & self . sources )
227
+ Self :: build_internal ( self . defaults , self . overrides , & self . state . sources )
124
228
}
125
229
126
230
/// Reads all registered [`Source`]s.
@@ -132,7 +236,11 @@ impl ConfigBuilder {
132
236
/// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
133
237
/// this method returns error.
134
238
pub fn build_cloned ( & self ) -> Result < Config > {
135
- Self :: build_internal ( self . defaults . clone ( ) , self . overrides . clone ( ) , & self . sources )
239
+ Self :: build_internal (
240
+ self . defaults . clone ( ) ,
241
+ self . overrides . clone ( ) ,
242
+ & self . state . sources ,
243
+ )
136
244
}
137
245
138
246
fn build_internal (
@@ -158,3 +266,85 @@ impl ConfigBuilder {
158
266
Ok ( Config :: new ( cache) )
159
267
}
160
268
}
269
+
270
+ impl 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 ) -> ConfigBuilder < AsyncState >
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
+ pub fn add_async_source < T > ( mut self , source : T ) -> ConfigBuilder < AsyncState >
288
+ where
289
+ T : AsyncSource + Send + Sync + ' static ,
290
+ {
291
+ self . state . sources . push ( SourceType :: Async ( Box :: new ( source) ) ) ;
292
+ self
293
+ }
294
+
295
+ /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
296
+ ///
297
+ /// This is the method that invokes all I/O operations.
298
+ /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
299
+ ///
300
+ /// # Errors
301
+ /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
302
+ /// this method returns error.
303
+ pub async fn build ( self ) -> Result < Config > {
304
+ Self :: build_internal ( self . defaults , self . overrides , & self . state . sources ) . await
305
+ }
306
+
307
+ /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
308
+ ///
309
+ /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
310
+ /// Internally it clones data to achieve it.
311
+ ///
312
+ /// # Errors
313
+ /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
314
+ /// this method returns error.
315
+ pub async fn build_cloned ( & self ) -> Result < Config > {
316
+ Self :: build_internal (
317
+ self . defaults . clone ( ) ,
318
+ self . overrides . clone ( ) ,
319
+ & self . state . sources ,
320
+ )
321
+ . await
322
+ }
323
+
324
+ async fn build_internal (
325
+ defaults : HashMap < Expression , Value > ,
326
+ overrides : HashMap < Expression , Value > ,
327
+ sources : & [ SourceType ] ,
328
+ ) -> Result < Config > {
329
+ let mut cache: Value = HashMap :: < String , Value > :: new ( ) . into ( ) ;
330
+
331
+ // Add defaults
332
+ for ( key, val) in defaults. into_iter ( ) {
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
+ SourceType :: Async ( source) => source. collect_to ( & mut cache) . await ?,
340
+ }
341
+ }
342
+
343
+ // Add overrides
344
+ for ( key, val) in overrides. into_iter ( ) {
345
+ key. set ( & mut cache, val) ;
346
+ }
347
+
348
+ Ok ( Config :: new ( cache) )
349
+ }
350
+ }
0 commit comments