1use crate::assembler::{AssembledGroupInstance, AssembledSegment, AssembledTree};
15
16#[derive(Debug, Clone)]
18pub struct TransactionView {
19 pub tree: AssembledTree,
22 pub left_out: Vec<u32>,
25}
26
27fn kind(instance: &AssembledGroupInstance) -> Option<(&str, &str)> {
30 let entry = instance.segments.first()?;
31 let qualifier = entry
32 .elements
33 .first()
34 .and_then(|e| e.first())
35 .map_or("", String::as_str);
36 Some((entry.tag.as_str(), qualifier))
37}
38
39fn segment_numbers(instance: &AssembledGroupInstance, out: &mut Vec<u32>) {
40 let own = instance.segments.iter().chain(&instance.skipped_segments);
41 out.extend(own.filter_map(|s: &AssembledSegment| s.segment_number));
42 for group in &instance.child_groups {
43 for repetition in &group.repetitions {
44 segment_numbers(repetition, out);
45 }
46 }
47}
48
49impl AssembledTree {
50 pub fn transaction_view(&self, group_id: &str, index: usize) -> Option<TransactionView> {
54 let position = self.groups.iter().position(|g| g.group_id == group_id)?;
55 let group = &self.groups[position];
56 let own = group.repetitions.get(index)?;
57 let own_kind = kind(own);
58 let mut repetitions = vec![own.clone()];
59 let mut left_out = Vec::new();
60 for (i, repetition) in group.repetitions.iter().enumerate() {
61 if i == index {
62 continue;
63 }
64 if kind(repetition) == own_kind {
65 segment_numbers(repetition, &mut left_out);
66 } else {
67 repetitions.push(repetition.clone());
68 }
69 }
70 left_out.sort_unstable();
71 let mut groups = Vec::with_capacity(self.groups.len());
72 for (i, g) in self.groups.iter().enumerate() {
73 if i == position {
74 let mut view = g.clone_shallow();
75 view.repetitions = std::mem::take(&mut repetitions);
76 groups.push(view);
77 } else {
78 groups.push(g.clone());
79 }
80 }
81 Some(TransactionView {
82 tree: AssembledTree {
83 segments: self.segments.clone(),
84 groups,
85 post_group_start: self.post_group_start,
86 inter_group_segments: self.inter_group_segments.clone(),
87 },
88 left_out,
89 })
90 }
91}
92
93impl crate::assembler::AssembledGroup {
94 fn clone_shallow(&self) -> Self {
96 Self {
97 group_id: self.group_id.clone(),
98 repetitions: Vec::new(),
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::assembler::AssembledGroup;
107
108 fn seg(text: &str, number: u32) -> AssembledSegment {
109 let mut parts = text.split('+');
110 AssembledSegment {
111 tag: parts.next().unwrap().to_string(),
112 elements: parts.map(|e| vec![e.to_string()]).collect(),
113 mig_number: None,
114 segment_number: Some(number),
115 }
116 }
117
118 fn inst(
119 segments: Vec<AssembledSegment>,
120 child_groups: Vec<AssembledGroup>,
121 ) -> AssembledGroupInstance {
122 AssembledGroupInstance {
123 segments,
124 child_groups,
125 entry_mig_number: None,
126 variant_mig_numbers: vec![],
127 skipped_segments: vec![],
128 skipped_positions: vec![],
129 }
130 }
131
132 fn sg8(seq: &str, number: u32) -> AssembledGroup {
133 AssembledGroup {
134 group_id: "SG8".into(),
135 repetitions: vec![inst(vec![seg(seq, number)], vec![])],
136 }
137 }
138
139 fn message() -> AssembledTree {
141 AssembledTree {
142 segments: vec![seg("BGM+E01", 1)],
143 groups: vec![
144 AssembledGroup {
145 group_id: "SG2".into(),
146 repetitions: vec![inst(vec![seg("NAD+MS", 2)], vec![])],
147 },
148 AssembledGroup {
149 group_id: "SG4".into(),
150 repetitions: vec![
151 inst(vec![seg("IDE+Z01", 3)], vec![]),
152 inst(vec![seg("IDE+24", 4)], vec![sg8("SEQ+Z01", 5)]),
153 inst(vec![seg("IDE+24", 6)], vec![sg8("SEQ+Z02", 7)]),
154 inst(vec![seg("IDE+24", 8)], vec![sg8("SEQ+Z03", 9)]),
155 ],
156 },
157 ],
158 post_group_start: 1,
159 inter_group_segments: Default::default(),
160 }
161 }
162
163 fn entries(tree: &AssembledTree) -> Vec<String> {
164 tree.groups[1]
165 .repetitions
166 .iter()
167 .map(|r| format!("{}+{}", r.segments[0].tag, r.segments[0].elements[0][0]))
168 .collect()
169 }
170
171 #[test]
172 fn a_transaction_sees_itself_first_and_the_list_but_no_other_transaction() {
173 let view = message().transaction_view("SG4", 2).unwrap();
174 assert_eq!(entries(&view.tree), ["IDE+24", "IDE+Z01"]);
175 assert_eq!(
176 view.tree.groups[1].repetitions[0].segments[0].segment_number,
177 Some(6)
178 );
179 assert_eq!(view.left_out, [4, 5, 8, 9]);
180 assert_eq!(view.tree.groups[0], message().groups[0]);
182 assert_eq!(view.tree.segments, message().segments);
183 }
184
185 #[test]
186 fn the_list_sees_every_transaction() {
187 let view = message().transaction_view("SG4", 0).unwrap();
188 assert_eq!(
189 entries(&view.tree),
190 ["IDE+Z01", "IDE+24", "IDE+24", "IDE+24"]
191 );
192 assert!(view.left_out.is_empty());
193 }
194
195 #[test]
196 fn no_such_group_or_repetition_is_no_view() {
197 assert!(message().transaction_view("SG5", 0).is_none());
198 assert!(message().transaction_view("SG4", 4).is_none());
199 }
200}