1use std::collections::HashMap;
15
16use crate::assembler::{AssembledGroup, AssembledGroupInstance, AssembledSegment, AssembledTree};
17use crate::tokenize::OwnedSegment;
18
19#[derive(Debug, Clone)]
21pub struct TransactionView {
22 pub tree: AssembledTree,
25 pub left_out: Vec<u32>,
28}
29
30fn kind(instance: &AssembledGroupInstance) -> Option<(&str, &str)> {
33 let entry = instance.segments.first()?;
34 let qualifier = entry
35 .elements
36 .first()
37 .and_then(|e| e.first())
38 .map_or("", String::as_str);
39 Some((entry.tag.as_str(), qualifier))
40}
41
42fn segment_numbers(instance: &AssembledGroupInstance, out: &mut Vec<u32>) {
43 let own = instance.segments.iter().chain(&instance.skipped_segments);
44 out.extend(own.filter_map(|s: &AssembledSegment| s.segment_number));
45 for group in &instance.child_groups {
46 for repetition in &group.repetitions {
47 segment_numbers(repetition, out);
48 }
49 }
50}
51
52impl AssembledTree {
53 pub fn transaction_view(&self, group_id: &str, index: usize) -> Option<TransactionView> {
57 let position = self.groups.iter().position(|g| g.group_id == group_id)?;
58 let group = &self.groups[position];
59 let own = group.repetitions.get(index)?;
60 let own_kind = kind(own);
61 let mut repetitions = vec![own.clone()];
62 let mut left_out = Vec::new();
63 for (i, repetition) in group.repetitions.iter().enumerate() {
64 if i == index {
65 continue;
66 }
67 if kind(repetition) == own_kind {
68 segment_numbers(repetition, &mut left_out);
69 } else {
70 repetitions.push(repetition.clone());
71 }
72 }
73 left_out.sort_unstable();
74 let mut groups = Vec::with_capacity(self.groups.len());
75 for (i, g) in self.groups.iter().enumerate() {
76 if i == position {
77 let mut view = g.clone_shallow();
78 view.repetitions = std::mem::take(&mut repetitions);
79 groups.push(view);
80 } else {
81 groups.push(g.clone());
82 }
83 }
84 Some(TransactionView {
85 tree: AssembledTree {
86 segments: self.segments.clone(),
87 groups,
88 post_group_start: self.post_group_start,
89 inter_group_segments: self.inter_group_segments.clone(),
90 },
91 left_out,
92 })
93 }
94}
95
96#[derive(Debug, Clone)]
99pub struct TransactionSegmentsView {
100 pub tree: AssembledTree,
102 pub segments: Vec<OwnedSegment>,
105}
106
107#[derive(Debug)]
117pub struct TransactionViews<'t> {
118 tree: &'t AssembledTree,
119 segments: &'t [OwnedSegment],
120 groups: Vec<TransactionGroupIndex>,
121}
122
123#[derive(Debug)]
124struct TransactionGroupIndex {
125 position: usize,
127 kind_of: Vec<usize>,
129 others: Vec<Vec<usize>>,
131 shared: Vec<Vec<usize>>,
134 own: Vec<Vec<usize>>,
137}
138
139impl AssembledTree {
140 pub fn transaction_views<'t>(
145 &'t self,
146 segments: &'t [OwnedSegment],
147 is_transaction_group: impl Fn(&str) -> bool,
148 ) -> TransactionViews<'t> {
149 let groups = self
150 .groups
151 .iter()
152 .enumerate()
153 .filter(|(_, g)| is_transaction_group(&g.group_id))
154 .map(|(position, g)| TransactionGroupIndex::new(position, g, segments))
155 .collect();
156 TransactionViews {
157 tree: self,
158 segments,
159 groups,
160 }
161 }
162}
163
164impl TransactionGroupIndex {
165 fn new(position: usize, group: &AssembledGroup, segments: &[OwnedSegment]) -> Self {
166 let mut kinds: Vec<Option<(&str, &str)>> = Vec::new();
167 let kind_of: Vec<usize> = group
168 .repetitions
169 .iter()
170 .map(|repetition| {
171 let k = kind(repetition);
172 kinds
173 .iter()
174 .position(|known| *known == k)
175 .unwrap_or_else(|| {
176 kinds.push(k);
177 kinds.len() - 1
178 })
179 })
180 .collect();
181 let others = (0..kinds.len())
182 .map(|k| (0..kind_of.len()).filter(|&r| kind_of[r] != k).collect())
183 .collect();
184
185 let mut holders: HashMap<u32, Vec<usize>> = HashMap::new();
187 let mut numbers = Vec::new();
188 for (r, repetition) in group.repetitions.iter().enumerate() {
189 numbers.clear();
190 segment_numbers(repetition, &mut numbers);
191 for &n in &numbers {
192 let held = holders.entry(n).or_default();
193 if held.last() != Some(&r) {
194 held.push(r);
195 }
196 }
197 }
198
199 let mut shared = vec![Vec::new(); kinds.len()];
202 let mut own = vec![Vec::new(); kind_of.len()];
203 for (i, segment) in segments.iter().enumerate() {
204 let held = holders
205 .get(&segment.segment_number)
206 .map_or(&[][..], Vec::as_slice);
207 for (k, shared) in shared.iter_mut().enumerate() {
208 let mut of_kind = held.iter().filter(|&&r| kind_of[r] == k);
209 match of_kind.next() {
210 None => shared.push(i),
211 Some(&r) if of_kind.all(|&other| other == r) => own[r].push(i),
212 Some(_) => {}
215 }
216 }
217 }
218 Self {
219 position,
220 kind_of,
221 others,
222 shared,
223 own,
224 }
225 }
226}
227
228impl TransactionViews<'_> {
229 pub fn view(&self, group_id: &str, index: usize) -> Option<TransactionSegmentsView> {
234 let index_of = self
235 .groups
236 .iter()
237 .find(|g| self.tree.groups[g.position].group_id == group_id)?;
238 let group = &self.tree.groups[index_of.position];
239 let own = group.repetitions.get(index)?;
240 let k = index_of.kind_of[index];
241
242 let mut repetitions = Vec::with_capacity(1 + index_of.others[k].len());
243 repetitions.push(own.clone());
244 repetitions.extend(
245 index_of.others[k]
246 .iter()
247 .map(|&r| group.repetitions[r].clone()),
248 );
249 let groups = self
250 .tree
251 .groups
252 .iter()
253 .enumerate()
254 .map(|(i, g)| {
255 if i == index_of.position {
256 AssembledGroup {
257 group_id: g.group_id.clone(),
258 repetitions: std::mem::take(&mut repetitions),
259 }
260 } else {
261 g.clone()
262 }
263 })
264 .collect();
265
266 let (shared, own) = (&index_of.shared[k], &index_of.own[index]);
268 let mut segments = Vec::with_capacity(shared.len() + own.len());
269 let (mut s, mut o) = (0, 0);
270 while s < shared.len() || o < own.len() {
271 let next = if o == own.len() || (s < shared.len() && shared[s] < own[o]) {
272 s += 1;
273 shared[s - 1]
274 } else {
275 o += 1;
276 own[o - 1]
277 };
278 segments.push(self.segments[next].clone());
279 }
280
281 Some(TransactionSegmentsView {
282 tree: AssembledTree {
283 segments: self.tree.segments.clone(),
284 groups,
285 post_group_start: self.tree.post_group_start,
286 inter_group_segments: self.tree.inter_group_segments.clone(),
287 },
288 segments,
289 })
290 }
291}
292
293impl AssembledGroup {
294 fn clone_shallow(&self) -> Self {
296 Self {
297 group_id: self.group_id.clone(),
298 repetitions: Vec::new(),
299 }
300 }
301}
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306 use crate::assembler::AssembledGroup;
307
308 fn seg(text: &str, number: u32) -> AssembledSegment {
309 let mut parts = text.split('+');
310 AssembledSegment {
311 tag: parts.next().unwrap().to_string(),
312 elements: parts.map(|e| vec![e.to_string()]).collect(),
313 mig_number: None,
314 segment_number: Some(number),
315 }
316 }
317
318 fn inst(
319 segments: Vec<AssembledSegment>,
320 child_groups: Vec<AssembledGroup>,
321 ) -> AssembledGroupInstance {
322 AssembledGroupInstance {
323 segments,
324 child_groups,
325 entry_mig_number: None,
326 variant_mig_numbers: vec![],
327 skipped_segments: vec![],
328 skipped_positions: vec![],
329 }
330 }
331
332 fn sg8(seq: &str, number: u32) -> AssembledGroup {
333 AssembledGroup {
334 group_id: "SG8".into(),
335 repetitions: vec![inst(vec![seg(seq, number)], vec![])],
336 }
337 }
338
339 fn message() -> AssembledTree {
341 AssembledTree {
342 segments: vec![seg("BGM+E01", 1)],
343 groups: vec![
344 AssembledGroup {
345 group_id: "SG2".into(),
346 repetitions: vec![inst(vec![seg("NAD+MS", 2)], vec![])],
347 },
348 AssembledGroup {
349 group_id: "SG4".into(),
350 repetitions: vec![
351 inst(vec![seg("IDE+Z01", 3)], vec![]),
352 inst(vec![seg("IDE+24", 4)], vec![sg8("SEQ+Z01", 5)]),
353 inst(vec![seg("IDE+24", 6)], vec![sg8("SEQ+Z02", 7)]),
354 inst(vec![seg("IDE+24", 8)], vec![sg8("SEQ+Z03", 9)]),
355 ],
356 },
357 ],
358 post_group_start: 1,
359 inter_group_segments: Default::default(),
360 }
361 }
362
363 fn entries(tree: &AssembledTree) -> Vec<String> {
364 tree.groups[1]
365 .repetitions
366 .iter()
367 .map(|r| format!("{}+{}", r.segments[0].tag, r.segments[0].elements[0][0]))
368 .collect()
369 }
370
371 #[test]
372 fn a_transaction_sees_itself_first_and_the_list_but_no_other_transaction() {
373 let view = message().transaction_view("SG4", 2).unwrap();
374 assert_eq!(entries(&view.tree), ["IDE+24", "IDE+Z01"]);
375 assert_eq!(
376 view.tree.groups[1].repetitions[0].segments[0].segment_number,
377 Some(6)
378 );
379 assert_eq!(view.left_out, [4, 5, 8, 9]);
380 assert_eq!(view.tree.groups[0], message().groups[0]);
382 assert_eq!(view.tree.segments, message().segments);
383 }
384
385 #[test]
386 fn the_list_sees_every_transaction() {
387 let view = message().transaction_view("SG4", 0).unwrap();
388 assert_eq!(
389 entries(&view.tree),
390 ["IDE+Z01", "IDE+24", "IDE+24", "IDE+24"]
391 );
392 assert!(view.left_out.is_empty());
393 }
394
395 fn segments(tree: &AssembledTree) -> Vec<OwnedSegment> {
398 fn collect(instance: &AssembledGroupInstance, out: &mut Vec<OwnedSegment>) {
399 for s in &instance.segments {
400 out.push(OwnedSegment {
401 id: s.tag.clone(),
402 elements: s.elements.clone(),
403 segment_number: s.segment_number.unwrap(),
404 });
405 }
406 for g in &instance.child_groups {
407 g.repetitions.iter().for_each(|r| collect(r, out));
408 }
409 }
410 let mut out: Vec<OwnedSegment> = Vec::new();
411 let root = inst(tree.segments.clone(), tree.groups.clone());
412 collect(&root, &mut out);
413 out.push(OwnedSegment {
414 id: "UNT".into(),
415 elements: vec![],
416 segment_number: 10,
417 });
418 out.sort_by_key(|s| s.segment_number);
419 out
420 }
421
422 #[test]
423 fn prepared_views_are_the_views_with_the_segments_they_keep() {
424 let tree = message();
425 let all = segments(&tree);
426 let views = tree.transaction_views(&all, |g| g == "SG4");
427 for index in 0..4 {
428 let expected = tree.transaction_view("SG4", index).unwrap();
429 let view = views.view("SG4", index).unwrap();
430 assert_eq!(view.tree.groups, expected.tree.groups, "view {index}");
431 assert_eq!(view.tree.segments, expected.tree.segments);
432 let kept: Vec<OwnedSegment> = all
433 .iter()
434 .filter(|s| expected.left_out.binary_search(&s.segment_number).is_err())
435 .cloned()
436 .collect();
437 assert_eq!(view.segments, kept, "view {index}");
438 }
439 let numbers = |index| -> Vec<u32> {
440 let view = views.view("SG4", index).unwrap();
441 view.segments.iter().map(|s| s.segment_number).collect()
442 };
443 assert_eq!(numbers(2), [1, 2, 3, 6, 7, 10]);
444 assert_eq!(numbers(0), (1..=10).collect::<Vec<_>>());
445 assert!(views.view("SG4", 4).is_none());
446 assert!(views.view("SG2", 0).is_none());
447 }
448
449 #[test]
450 fn no_such_group_or_repetition_is_no_view() {
451 assert!(message().transaction_view("SG5", 0).is_none());
452 assert!(message().transaction_view("SG4", 4).is_none());
453 }
454}