@@ -81,6 +81,39 @@ impl<K: Hash + Eq + Clone, V: Merge + Clone> Merge for HashMap<K, V> {
81
81
}
82
82
}
83
83
84
+ /// Moving version of [`Merge::merge`], to produce slightly nicer test output
85
+ pub fn merge < T : Merge > ( mut overrides : T , defaults : & T ) -> T {
86
+ overrides. merge ( defaults) ;
87
+ overrides
88
+ }
89
+
90
+ /// Composable version of [`Merge::merge`] that allows reducing a sequence of `Option<mut& T>`.
91
+ ///
92
+ /// Example:
93
+ ///
94
+ /// ```
95
+ /// use stackable_operator::config::merge::{Merge, chainable_merge};
96
+ /// #[derive(Clone, Default, Merge, PartialEq)]
97
+ /// struct MyConfig {
98
+ /// field: Option<i32>,
99
+ /// }
100
+ ///
101
+ /// let mut c0 = None;
102
+ /// let mut c1 = Some(MyConfig { field: Some(23) });
103
+ /// let mut c2 = Some(MyConfig { field: Some(7) });
104
+ ///
105
+ /// let merged = [c0.as_mut(), c1.as_mut(), c2.as_mut()]
106
+ /// .into_iter()
107
+ /// .flatten()
108
+ /// .reduce(|old, new| chainable_merge(new, old));
109
+ ///
110
+ /// assert_eq!(7, merged.unwrap().field.unwrap());
111
+ /// ```
112
+ pub fn chainable_merge < ' a , T : Merge + Clone > ( this : & ' a mut T , defaults : & T ) -> & ' a mut T {
113
+ this. merge ( defaults) ;
114
+ this
115
+ }
116
+
84
117
/// A marker trait for types that are merged atomically (as one single value) rather than
85
118
/// trying to merge each field individually
86
119
pub trait Atomic : Clone { }
@@ -113,13 +146,7 @@ impl<T: Atomic> Merge for Option<T> {
113
146
mod tests {
114
147
use std:: collections:: { BTreeMap , HashMap } ;
115
148
116
- use super :: Merge ;
117
-
118
- /// Moving version of [`Merge::merge`], to produce slightly nicer test output
119
- fn merge < T : Merge > ( mut overrides : T , defaults : & T ) -> T {
120
- overrides. merge ( defaults) ;
121
- overrides
122
- }
149
+ use super :: { merge, Merge } ;
123
150
124
151
#[ derive( Debug , PartialEq , Eq , Clone ) ]
125
152
struct Accumulator ( u8 ) ;
0 commit comments