1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Merging two `docker-compose.yml` files together.

use std::collections::BTreeMap;
use std::collections::btree_map;
use std::marker::{PhantomData, Sized};

/// This trait is implemented by types that can be merged
pub trait MergeOverride: Clone + Sized {
    /// Given this value and an override value, merge the override value
    /// into this one, producing a new value.
    ///
    /// The default implementation just ignores the original value in favor
    /// of `ovr`, so it's appropriate for simple scalar types.  More
    /// complex types will require a custom implementation.
    fn merge_override(&self, ovr: &Self) -> Self {
        ovr.to_owned()
    }
}

macro_rules! assert_merge {
    ($ty:ty, $value1:expr, $value2:expr, $expected: expr) => {
        assert_eq!(($value1 as $ty).merge_override(&($value2 as $ty)),
                   ($expected as $ty));
    }
}

impl MergeOverride for u16 {}
impl MergeOverride for u32 {}
impl MergeOverride for bool {}
impl MergeOverride for String {}
impl<T> MergeOverride for PhantomData<T> {}

#[test]
#[allow(trivial_numeric_casts)]
fn simple_types_are_replaced() {
    assert_merge!(u16, 1, 2, 2);
    assert_merge!(bool, false, true, true);
    assert_merge!(String, "s1".to_owned(), "s2".to_owned(), "s2".to_owned());
}

impl<T: MergeOverride> MergeOverride for Option<T> {
    /// If both option values are present, call `merge_override`
    /// recursively.  If only one value is present, use that one.  If
    /// neither is present, return `None`.
    fn merge_override(&self, ovr: &Self) -> Self {
        match (self, ovr) {
            (&Some(ref x), &Some(ref y)) => Some(x.merge_override(y)),
            (&Some(ref x), &None) => Some(x.to_owned()),
            (&None, &Some(ref y)) => Some(y.to_owned()),
            (&None, &None) => None,
        }
    }
}

#[test]
fn option_uses_second_value_if_not_none() {
    assert_merge!(Option<bool>, Some(false), Some(true), Some(true));
    assert_merge!(Option<bool>, Some(false), None,       Some(false));
    assert_merge!(Option<bool>, None,        Some(true), Some(true));
    assert_merge!(Option<bool>, None,        None,       None);

    // Check complex recursive merge, too.
    assert_merge!(Option<Vec<bool>>,
                  Some(vec!(false)), Some(vec!(true)),
                  Some(vec!(false, true)));
}

impl<T: MergeOverride> MergeOverride for Vec<T> {
    /// Appends `ovr` to `self`, creating a new list.
    fn merge_override(&self, ovr: &Self) -> Self {
        let mut result = self.clone();
        result.extend_from_slice(ovr as &[T]);
        result
    }
}

#[test]
fn vec_appends_new_values() {
    assert_merge!(Vec<bool>, vec!(false), vec!(true), vec!(false, true));
}

impl<K: Ord + Clone, T: MergeOverride> MergeOverride for BTreeMap<K, T> {
    /// Merges `ovr` into `self`, recursively merging values if present in
    /// both, and returns a new `BTreeMap`.
    fn merge_override(&self, ovr: &Self) -> Self {
        let mut result = self.clone();
        for (ovr_key, ovr_val) in ovr {
            match result.entry(ovr_key.to_owned()) {
                btree_map::Entry::Vacant(vacant) => {
                    vacant.insert(ovr_val.clone());
                }
                btree_map::Entry::Occupied(mut occupied) => {
                    let merged = occupied.get().merge_override(ovr_val);
                    occupied.insert(merged);
                }
            }
        }
        result
    }
}

#[test]
fn btree_map_merges_by_key() {
    let mut map1 = BTreeMap::new();
    map1.insert("a", vec!(false));
    map1.insert("c", vec!(false));
    let mut map2 = BTreeMap::new();
    map2.insert("b", vec!(true));
    map2.insert("c", vec!(true));
    let mut expected = BTreeMap::new();
    expected.insert("a", vec!(false));
    expected.insert("b", vec!(true));
    expected.insert("c", vec!(false, true));
    assert_merge!(BTreeMap<&'static str, Vec<bool>>, map1, map2, expected);
}

/// Derive `MergeOverride` for a custom struct type, by recursively merging
/// all fields.
macro_rules! derive_merge_override_for {
    ($ty:ident, { $( $field:ident ),+ }) => {
        /// Recursive merge all fields in the structure.
        impl MergeOverride for $ty {
            fn merge_override(&self, ovr: &Self) -> Self {
                $ty {
                    $( $field: self.$field.merge_override(&ovr.$field) ),+
                }
            }
        }
    }
}