1use crate::node::base::BaseNode;
9use crate::node::branch::BranchNode;
10use crate::node::NodeRef;
11
12use super::{HeuristicMatching, Matching};
13
14pub struct TriMatching {
22 left_root: NodeRef,
23 right_root: NodeRef,
24 base_root: NodeRef,
25}
26
27impl TriMatching {
28 pub fn new(left: NodeRef, base: NodeRef, right: NodeRef) -> Self {
30 Self::with_matching::<HeuristicMatching, HeuristicMatching>(left, base, right)
31 }
32
33 pub fn with_copy_threshold(
39 left: NodeRef,
40 base: NodeRef,
41 right: NodeRef,
42 copy_threshold: i32,
43 ) -> Self {
44 let mut right_matcher = HeuristicMatching::with_copy_threshold(copy_threshold);
46 right_matcher.build_matching(&base, &right);
47
48 Self::swap_left_right(&base);
50
51 let mut left_matcher = HeuristicMatching::with_copy_threshold(copy_threshold);
53 left_matcher.build_matching(&base, &left);
54
55 Self::set_partners(&left, false);
57 Self::set_partners(&right, true);
58
59 TriMatching {
60 left_root: left,
61 right_root: right,
62 base_root: base,
63 }
64 }
65
66 pub fn with_matching<L: Matching + Default, R: Matching + Default>(
71 left: NodeRef,
72 base: NodeRef,
73 right: NodeRef,
74 ) -> Self {
75 let mut right_matcher = R::default();
77 right_matcher.build_matching(&base, &right);
78
79 Self::swap_left_right(&base);
83
84 let mut left_matcher = L::default();
86 left_matcher.build_matching(&base, &left);
87
88 Self::set_partners(&left, false);
90 Self::set_partners(&right, true);
91
92 TriMatching {
93 left_root: left,
94 right_root: right,
95 base_root: base,
96 }
97 }
98
99 fn swap_left_right(base: &NodeRef) {
105 BaseNode::swap_left_right_matchings(base);
106
107 let children: Vec<NodeRef> = base.borrow().children().to_vec();
108 for child in children {
109 Self::swap_left_right(&child);
110 }
111 }
112
113 fn set_partners(node: &NodeRef, partner_in_left: bool) {
122 if let Some(base_match) = BranchNode::base_match(node) {
123 let partners = if partner_in_left {
125 Some(BaseNode::left(&base_match))
126 } else {
127 Some(BaseNode::right(&base_match))
128 };
129 BranchNode::set_partners(node, partners);
130 } else {
131 BranchNode::set_partners(node, None);
132 }
133
134 let children: Vec<NodeRef> = node.borrow().children().to_vec();
136 for child in children {
137 Self::set_partners(&child, partner_in_left);
138 }
139 }
140
141 pub fn left_root(&self) -> &NodeRef {
143 &self.left_root
144 }
145
146 pub fn right_root(&self) -> &NodeRef {
148 &self.right_root
149 }
150
151 pub fn base_root(&self) -> &NodeRef {
153 &self.base_root
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160 use crate::node::{new_base_node, new_branch_node, NodeInner, XmlContent, XmlElement, XmlText};
161 use std::collections::HashMap;
162
163 fn make_element(name: &str) -> XmlContent {
164 XmlContent::Element(XmlElement::new(name.to_string(), HashMap::new()))
165 }
166
167 fn make_text(text: &str) -> XmlContent {
168 XmlContent::Text(XmlText::new(text))
169 }
170
171 #[test]
172 fn test_tri_matching_simple() {
173 let base_root = new_base_node(Some(make_element("root")));
179 let base_a = new_base_node(Some(make_element("a")));
180 NodeInner::add_child_to_ref(&base_root, base_a);
181
182 let left_root = new_branch_node(Some(make_element("root")));
183 let left_a = new_branch_node(Some(make_element("a")));
184 NodeInner::add_child_to_ref(&left_root, left_a.clone());
185
186 let right_root = new_branch_node(Some(make_element("root")));
187 let right_a = new_branch_node(Some(make_element("a")));
188 NodeInner::add_child_to_ref(&right_root, right_a.clone());
189
190 let matching = TriMatching::new(left_root.clone(), base_root.clone(), right_root.clone());
191
192 assert!(BranchNode::has_base_match(&left_a));
194 assert!(BranchNode::has_base_match(&right_a));
195
196 let left_partners = BranchNode::partners(&left_a);
198 assert!(left_partners.is_some());
199 let partners_borrowed = left_partners.unwrap();
200 assert_eq!(partners_borrowed.borrow().match_count(), 1);
201
202 assert_eq!(matching.left_root().borrow().id(), left_root.borrow().id());
204 assert_eq!(
205 matching.right_root().borrow().id(),
206 right_root.borrow().id()
207 );
208 assert_eq!(matching.base_root().borrow().id(), base_root.borrow().id());
209 }
210
211 #[test]
212 fn test_tri_matching_with_modifications() {
213 let base_root = new_base_node(Some(make_element("root")));
218 let base_a = new_base_node(Some(make_element("a")));
219 let base_text = new_base_node(Some(make_text("text")));
220 NodeInner::add_child_to_ref(&base_root, base_a.clone());
221 NodeInner::add_child_to_ref(&base_a, base_text);
222
223 let left_root = new_branch_node(Some(make_element("root")));
224 let left_a = new_branch_node(Some(make_element("a")));
225 let left_text = new_branch_node(Some(make_text("modified")));
226 NodeInner::add_child_to_ref(&left_root, left_a.clone());
227 NodeInner::add_child_to_ref(&left_a, left_text.clone());
228
229 let right_root = new_branch_node(Some(make_element("root")));
230 let right_a = new_branch_node(Some(make_element("a")));
231 let right_text = new_branch_node(Some(make_text("text")));
232 NodeInner::add_child_to_ref(&right_root, right_a.clone());
233 NodeInner::add_child_to_ref(&right_a, right_text.clone());
234
235 let _matching = TriMatching::new(left_root, base_root, right_root);
236
237 assert!(BranchNode::has_base_match(&left_a));
239 assert!(BranchNode::has_base_match(&right_a));
240
241 assert!(BranchNode::has_base_match(&right_text));
243
244 }
247
248 #[test]
249 fn test_tri_matching_unmatched_nodes() {
250 let base_root = new_base_node(Some(make_element("root")));
255 let base_a = new_base_node(Some(make_element("a")));
256 NodeInner::add_child_to_ref(&base_root, base_a);
257
258 let left_root = new_branch_node(Some(make_element("root")));
259 let left_a = new_branch_node(Some(make_element("a")));
260 let left_b = new_branch_node(Some(make_element("b")));
261 NodeInner::add_child_to_ref(&left_root, left_a.clone());
262 NodeInner::add_child_to_ref(&left_root, left_b.clone());
263
264 let right_root = new_branch_node(Some(make_element("root")));
265 let right_a = new_branch_node(Some(make_element("a")));
266 NodeInner::add_child_to_ref(&right_root, right_a.clone());
267
268 let _matching = TriMatching::new(left_root, base_root, right_root);
269
270 assert!(BranchNode::has_base_match(&left_a));
272 assert!(BranchNode::has_base_match(&right_a));
273
274 assert!(!BranchNode::has_base_match(&left_b));
276
277 assert!(BranchNode::partners(&left_b).is_none());
279 }
280}