1pub trait Merge {
4 fn merge(&self, other: &Self) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized;
5}
6
7pub trait MergeMut {
10 fn merge_mut(&mut self, other: &Self) -> Result<(), Box<dyn std::error::Error>>;
11}
12
13impl<T: Clone + Merge> Merge for Option<T> {
26 fn merge(&self, rhs: &Self) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
27 Ok(match (self, rhs) {
28 (Some(left), Some(right)) => Some(left.merge(right)?),
29 (Some(left), None) => Some(left.clone()),
30 (None, Some(right)) => Some(right.clone()),
31 (None, None) => None,
32 })
33 }
34}
35
36impl<T: Clone + Merge, E: Clone + Merge> Merge for Result<T, E> {
41 fn merge(&self, rhs: &Self) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
42 Ok(match (self, rhs) {
43 (Err(left), _) => Err(left.clone()),
44 (_, Err(right)) => Err(right.clone()),
45 (Ok(left), Ok(right)) => Ok(left.merge(right)?),
46 })
47 }
48}
49
50pub use merge_rs_derive::{Merge, MergeMut};
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[derive(Clone)]
57 struct MergeSpy(&'static str, bool);
58
59 impl MergeSpy {
60 fn new() -> Self {
61 Self::with_label("spy")
62 }
63
64 fn with_label(label: &'static str) -> Self {
65 MergeSpy(label, false)
66 }
67
68 fn is_merge_called(&self) -> bool {
69 self.1
70 }
71
72 fn label(&self) -> &str {
73 self.0
74 }
75 }
76
77 impl Merge for MergeSpy {
78 fn merge(&self, _: &Self) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
79 Ok(MergeSpy("merged", true))
80 }
81 }
82
83 type TestResult = Result<(), Box<dyn std::error::Error>>;
84
85 #[test]
86 fn test_option_merge_both_none() -> TestResult {
87 let left: Option<MergeSpy> = None;
88 let right: Option<MergeSpy> = None;
89
90 let actual = left.merge(&right)?;
91 assert!(actual.is_none());
92 Ok(())
93 }
94
95 #[test]
96 fn test_option_merge_left_none() -> TestResult {
97 let left = None;
98 let right = Some(MergeSpy::new());
99
100 let actual = left.merge(&right)?;
101 assert!(matches!(actual, Some(res) if !res.is_merge_called()));
102 Ok(())
103 }
104
105 #[test]
106 fn test_option_merge_right_none() -> TestResult {
107 let left = Some(MergeSpy::new());
108 let right = None;
109
110 let actual = left.merge(&right)?;
111 assert!(matches!(actual, Some(res) if !res.is_merge_called()));
112 Ok(())
113 }
114
115 #[test]
116 fn test_option_merge_both_some() -> TestResult {
117 let left = Some(MergeSpy::new());
118 let right = Some(MergeSpy::new());
119
120 let actual = left.merge(&right)?;
121 assert!(matches!(actual, Some(res) if res.is_merge_called()));
122 Ok(())
123 }
124
125 #[test]
126 fn test_result_merge_left_err() -> TestResult {
127 let left = Err(MergeSpy::with_label("left"));
128 let right = Ok(MergeSpy::with_label("right"));
129
130 let actual = left.merge(&right)?;
131 assert!(matches!(actual, Err(res) if res.label() == "left" && !res.is_merge_called()));
132 Ok(())
133 }
134
135 #[test]
136 fn test_result_merge_left_both_err() -> TestResult {
137 let left: Result<MergeSpy, MergeSpy> = Err(MergeSpy::with_label("left"));
138 let right: Result<MergeSpy, MergeSpy> = Err(MergeSpy::with_label("right"));
139
140 let actual = left.merge(&right)?;
141 assert!(matches!(actual, Err(res) if res.label() == "left" && !res.is_merge_called()));
142 Ok(())
143 }
144
145 #[test]
146 fn test_result_merge_right_err() -> TestResult {
147 let left = Ok(MergeSpy::with_label("left"));
148 let right = Err(MergeSpy::with_label("right"));
149
150 let actual = left.merge(&right)?;
151 assert!(matches!(actual, Err(res) if res.label() == "right" && !res.is_merge_called()));
152 Ok(())
153 }
154
155 #[test]
156 fn test_result_merge_both_ok() -> TestResult {
157 let left: Result<MergeSpy, MergeSpy> = Ok(MergeSpy::with_label("left"));
158 let right: Result<MergeSpy, MergeSpy> = Ok(MergeSpy::with_label("right"));
159
160 let actual = left.merge(&right)?;
161 assert!(matches!(actual, Ok(res) if res.is_merge_called()));
162 Ok(())
163 }
164}