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
use crate::{
    Combine, CombineByKey, Merge, MergeByKey, MergeCombine, MergeCombineByKey, ShallowMerge,
};

use std::hash::Hash;

fn merge_with<T>(lhs: &mut Option<T>, rhs: &Option<T>, merge: impl FnOnce(&mut T, &T))
where
    T: Clone,
{
    match (lhs, rhs) {
        (Some(lhs), Some(rhs)) => merge(lhs, rhs),
        (lhs @ None, rhs) => *lhs = rhs.clone(),
        (_, None) => (),
    }
}

impl<T> Merge for Option<T>
where
    T: Merge + Clone,
{
    fn merge(&mut self, template: &Self) {
        merge_with(self, template, |lhs, rhs| lhs.merge(rhs));
    }
}

impl<T> ShallowMerge for Option<T>
where
    T: Clone,
{
    fn shallow_merge(&mut self, template: &Self) {
        merge_with(self, template, |_, _| ());
    }
}

impl<T> Combine for Option<T>
where
    T: Combine + Clone,
{
    fn combine(&mut self, template: &Self) {
        merge_with(self, template, |lhs, rhs| lhs.combine(rhs));
    }
}

impl<T> MergeCombine for Option<T>
where
    T: MergeCombine + Clone,
{
    fn merge_combine(&mut self, template: &Self) {
        merge_with(self, template, |lhs, rhs| lhs.merge_combine(rhs));
    }
}

impl<T> MergeByKey for Option<T>
where
    T: MergeByKey + Clone,
{
    type Elem = T::Elem;

    fn merge_by_key<F, K>(&mut self, template: &Self, get_key: F)
    where
        F: FnMut(&Self::Elem) -> K,
        K: Hash + Eq,
    {
        merge_with(self, template, |lhs, rhs| lhs.merge_by_key(rhs, get_key));
    }
}

impl<T> MergeCombineByKey for Option<T>
where
    T: MergeCombineByKey + Clone,
{
    type Elem = T::Elem;

    fn merge_combine_by_key<F, K>(&mut self, template: &Self, get_key: F)
    where
        F: FnMut(&Self::Elem) -> K,
        K: Hash + Eq,
    {
        merge_with(self, template, |lhs, rhs| {
            lhs.merge_combine_by_key(rhs, get_key)
        });
    }
}

impl<T> CombineByKey for Option<T>
where
    T: CombineByKey + Clone,
{
    type Elem = T::Elem;

    fn combine_by_key<F, K>(&mut self, template: &Self, get_key: F)
    where
        F: FnMut(&Self::Elem) -> K,
        K: Hash + Eq,
    {
        merge_with(self, template, |lhs, rhs| lhs.combine_by_key(rhs, get_key));
    }
}