1#[derive(Clone, Debug, Default, Eq, PartialEq)]
3pub struct OrderedRawChildren {
4 children: Vec<RawChild>,
5}
6
7#[derive(Clone, Debug, Eq, PartialEq)]
8struct RawChild {
9 boundary: usize,
10 xml: Vec<u8>,
11}
12
13impl OrderedRawChildren {
14 pub fn push(&mut self, boundary: usize, raw_xml: Vec<u8>) {
16 self.children.push(RawChild {
17 boundary,
18 xml: raw_xml,
19 });
20 }
21
22 pub fn at(&self, boundary: usize) -> impl Iterator<Item = &[u8]> {
24 self.children
25 .iter()
26 .filter(move |child| child.boundary == boundary)
27 .map(|child| child.xml.as_slice())
28 }
29
30 pub fn is_empty(&self) -> bool {
32 self.children.is_empty()
33 }
34
35 pub fn shift_boundaries_from(&mut self, boundary: usize) {
38 for child in &mut self.children {
39 if child.boundary >= boundary {
40 child.boundary += 1;
41 }
42 }
43 }
44
45 pub fn at_reconciled<'a>(
49 &'a self,
50 boundary: usize,
51 offset: usize,
52 original_to_current: &'a [Option<usize>],
53 current_len: usize,
54 ) -> impl Iterator<Item = &'a [u8]> {
55 self.children
56 .iter()
57 .filter(move |child| {
58 if child.boundary < offset {
59 return false;
60 }
61 let original_index = child.boundary - offset;
62 let effective = original_to_current
63 .iter()
64 .skip(original_index)
65 .flatten()
66 .copied()
67 .next()
68 .unwrap_or(current_len);
69 effective == boundary
70 })
71 .map(|child| child.xml.as_slice())
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use oxml_core::raw_xml::{capture_element, capture_empty_element};
78 use quick_xml::events::{BytesEnd, BytesStart, Event};
79 use quick_xml::{Reader, Writer};
80
81 use super::OrderedRawChildren;
82
83 struct TestParent {
84 has_modelled_child: bool,
85 raw_children: OrderedRawChildren,
86 }
87
88 impl TestParent {
89 fn from_xml(xml: &[u8]) -> Self {
90 let mut reader = Reader::from_reader(xml);
91 let mut raw_children = OrderedRawChildren::default();
92 let mut has_modelled_child = false;
93 let mut boundary = 0;
94 let mut buffer = Vec::new();
95
96 loop {
97 match reader.read_event_into(&mut buffer).unwrap() {
98 Event::Start(element) if local_name(element.name().as_ref()) == b"known" => {
99 has_modelled_child = true;
100 boundary = 1;
101 reader.read_to_end(element.name()).unwrap();
102 }
103 Event::Empty(element) if local_name(element.name().as_ref()) == b"known" => {
104 has_modelled_child = true;
105 boundary = 1;
106 }
107 Event::Start(element) if local_name(element.name().as_ref()) != b"parent" => {
108 let raw = capture_element(&mut reader, &element).unwrap();
109 raw_children.push(boundary, raw);
110 }
111 Event::Empty(element) => {
112 let raw = capture_empty_element(&element).unwrap();
113 raw_children.push(boundary, raw);
114 }
115 Event::Eof => break,
116 _ => {}
117 }
118 buffer.clear();
119 }
120
121 Self {
122 has_modelled_child,
123 raw_children,
124 }
125 }
126
127 fn to_xml(&self) -> Vec<u8> {
128 let mut writer = Writer::new(Vec::new());
129 writer
130 .write_event(Event::Start(BytesStart::new("a:parent")))
131 .unwrap();
132 emit_raw(&mut writer, self.raw_children.at(0));
133 if self.has_modelled_child {
134 writer
135 .write_event(Event::Empty(BytesStart::new("a:known")))
136 .unwrap();
137 }
138 emit_raw(&mut writer, self.raw_children.at(1));
139 writer
140 .write_event(Event::End(BytesEnd::new("a:parent")))
141 .unwrap();
142 writer.into_inner()
143 }
144 }
145
146 fn emit_raw<'a>(writer: &mut Writer<Vec<u8>>, children: impl Iterator<Item = &'a [u8]>) {
147 for child in children {
148 writer.get_mut().extend_from_slice(child);
149 }
150 }
151
152 fn local_name(name: &[u8]) -> &[u8] {
153 name.rsplit(|byte| *byte == b':').next().unwrap_or(name)
154 }
155
156 #[test]
157 fn modelled_child_between_two_unmodelled_children_keeps_all_three_slots() {
158 let parent = TestParent::from_xml(br#"<z:parent><x:first/><z:known/><y:last/></z:parent>"#);
159
160 assert_eq!(
161 parent.to_xml(),
162 br#"<a:parent><x:first/><a:known/><y:last/></a:parent>"#
163 );
164 }
165
166 #[test]
167 fn multiple_raw_children_at_one_slot_preserve_document_order() {
168 let parent =
169 TestParent::from_xml(br#"<z:parent><x:first/><y:second/><z:known/></z:parent>"#);
170
171 assert_eq!(
172 parent.to_xml(),
173 br#"<a:parent><x:first/><y:second/><a:known/></a:parent>"#
174 );
175 }
176
177 #[test]
178 fn raw_subtrees_are_reemitted_byte_for_byte() {
179 let parent = TestParent::from_xml(
180 br#"<z:parent><x:item x:id="7"><x:child>one & two</x:child><!--note--></x:item><z:known/></z:parent>"#,
181 );
182
183 assert_eq!(
184 parent.to_xml(),
185 br#"<a:parent><x:item x:id="7"><x:child>one & two</x:child><!--note--></x:item><a:known/></a:parent>"#
186 );
187 }
188
189 #[test]
190 fn raw_children_after_the_last_modelled_child_are_not_dropped() {
191 let parent =
192 TestParent::from_xml(br#"<z:parent><z:known/><x:last x:value="kept"/></z:parent>"#);
193
194 assert!(!parent.raw_children.is_empty());
195 assert_eq!(
196 parent.to_xml(),
197 br#"<a:parent><a:known/><x:last x:value="kept"/></a:parent>"#
198 );
199 }
200}