@@ -196,41 +196,97 @@ macro_rules! create_config {
196196 $( pub $i: $ty) ,+
197197 }
198198
199- // Just like the Config struct but with each property wrapped
200- // as Option<T>. This is used to parse a rustfmt.toml that doesn't
201- // specity all properties of `Config`.
202- // We first parse into `ParsedConfig`, then create a default `Config`
203- // and overwrite the properties with corresponding values from `ParsedConfig`
199+ /// Equivalent to `Config` except that each field is wrapped in an `Option`.
200+ ///
201+ /// This can be decoded into from TOML, and then later merged into a `Config` or another
202+ /// `PartialConfig`.
203+ ///
204+ /// # Examples
205+ ///
206+ /// Decode a TOML value into a `PartialConfig`:
207+ ///
208+ /// ```ignore
209+ /// extern crate toml;
210+ /// let toml_str = r#"
211+ /// ideal_width = 72
212+ /// "#;
213+ ///
214+ /// let partial: PartialConfig = toml::decode_str(toml_str);
215+ /// ```
216+ ///
217+ /// Later, merge the `PartialConfig` into the default `Config`:
218+ ///
219+ /// ```ignore
220+ /// # extern crate toml;
221+ /// # use config::{Config, PartialConfig};
222+ ///
223+ /// # let toml_value = "abc = 3".parse().expect("Could not parse TOML");
224+ /// # let partial: PartialConfig = toml::decode(toml_value);
225+ /// let config = Config::Default().merge(partial);
226+ /// assert_eq!(72, config.ideal_width);
227+ /// ```
204228 #[ derive( RustcDecodable , Clone ) ]
205- pub struct ParsedConfig {
229+ pub struct PartialConfig {
206230 $( pub $i: Option <$ty>) ,+
207231 }
208232
233+ impl PartialConfig {
234+
235+ /// Create a `PartialConfig` with all fields set to `None`.
236+ pub fn new( ) -> PartialConfig {
237+ PartialConfig {
238+ $(
239+ $i: None ,
240+ ) +
241+ }
242+
243+ }
244+
245+ /// Merge `other` into `self, overwriting fields in `self` with any non-`None` fields
246+ /// in `other`.
247+ pub fn merge( & mut self , other: & PartialConfig ) -> & mut PartialConfig {
248+ $(
249+ if other. $i. is_some( ) {
250+ self . $i = other. $i;
251+ }
252+ ) +
253+ self
254+ }
255+ }
256+
257+ impl Default for PartialConfig {
258+ fn default ( ) -> PartialConfig {
259+ PartialConfig :: new( )
260+ }
261+ }
262+
263+ /// Applies settings in `partial` on top of the default `Config`.
264+ impl From <PartialConfig > for Config {
265+ fn from( partial: PartialConfig ) -> Config {
266+ Config :: default ( ) . merge( & partial)
267+ }
268+ }
269+
270+ /// Applies settings in `partial` on top of the default `Config`.
271+ impl <' a> From <& ' a PartialConfig > for Config {
272+ fn from( partial: & ' a PartialConfig ) -> Config {
273+ Config :: default ( ) . merge( partial)
274+ }
275+ }
276+
209277 impl Config {
210278
211- fn fill_from_parsed_config( mut self , parsed: ParsedConfig ) -> Config {
279+ /// Merge `partial` into `self, overwriting fields in `self` with any non-`None` fields
280+ /// in `partial`.
281+ pub fn merge( mut self , partial: & PartialConfig ) -> Config {
212282 $(
213- if let Some ( val) = parsed . $i {
283+ if let Some ( val) = partial . $i {
214284 self . $i = val;
215285 }
216286 ) +
217287 self
218288 }
219289
220- pub fn from_toml( toml: & str ) -> Config {
221- let parsed = toml. parse( ) . unwrap( ) ;
222- let parsed_config: ParsedConfig = match toml:: decode( parsed) {
223- Some ( decoded) => decoded,
224- None => {
225- println!( "Decoding config file failed. Config:\n {}" , toml) ;
226- let parsed: toml:: Value = toml. parse( ) . unwrap( ) ;
227- println!( "\n \n Parsed:\n {:?}" , parsed) ;
228- panic!( ) ;
229- }
230- } ;
231- Config :: default ( ) . fill_from_parsed_config( parsed_config)
232- }
233-
234290 pub fn override_value( & mut self , key: & str , val: & str ) {
235291 match key {
236292 $(
@@ -347,3 +403,37 @@ create_config! {
347403 write_mode: WriteMode , WriteMode :: Default ,
348404 "What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage" ;
349405}
406+
407+ #[ cfg( test) ]
408+ mod tests {
409+ use super :: * ;
410+ #[ test]
411+ fn test_config_merge_overrides ( ) {
412+ let config = Config :: default ( ) . merge ( & PartialConfig {
413+ ideal_width : Some ( 37 ) ,
414+ ..PartialConfig :: default ( )
415+ } ) ;
416+ assert_eq ! ( 37 , config. ideal_width) ;
417+ }
418+
419+ #[ test]
420+ fn test_partial_config_merge_overrides ( ) {
421+ let mut config = PartialConfig :: default ( ) ;
422+ config. merge ( & PartialConfig { ideal_width : Some ( 37 ) , ..PartialConfig :: default ( ) } ) ;
423+ assert_eq ! ( Some ( 37 ) , config. ideal_width) ;
424+ }
425+
426+ #[ test]
427+ fn test_config_merge_does_not_override_if_none ( ) {
428+ let mut config = Config { ideal_width : 37 , ..Config :: default ( ) } ;
429+ config = config. merge ( & PartialConfig :: new ( ) ) ;
430+ assert_eq ! ( 37 , config. ideal_width) ;
431+ }
432+
433+ #[ test]
434+ fn test_partial_config_merge_does_not_override_if_none ( ) {
435+ let mut config = PartialConfig { ideal_width : Some ( 37 ) , ..PartialConfig :: default ( ) } ;
436+ config. merge ( & PartialConfig :: new ( ) ) ;
437+ assert_eq ! ( Some ( 37 ) , config. ideal_width) ;
438+ }
439+ }
0 commit comments