1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//! Group-scoped segment navigation trait.
use crate::segment::OwnedSegment;
/// Provides group-scoped segment access for condition evaluation.
///
/// Implementations translate hierarchical group paths (e.g., `["SG4", "SG8"]`)
/// into segment lookups scoped to a specific group instance.
pub trait GroupNavigator: Send + Sync {
/// Find all segments with the given tag within a specific group instance.
///
/// * `segment_id` - Segment tag to find (e.g., "SEQ", "CCI")
/// * `group_path` - Path of group IDs from root (e.g., `&["SG4", "SG8"]`)
/// * `instance_index` - Which repetition of the innermost group (0-based)
fn find_segments_in_group(
&self,
segment_id: &str,
group_path: &[&str],
instance_index: usize,
) -> Vec<OwnedSegment>;
/// Find segments matching a tag + qualifier within a group instance.
///
/// * `segment_id` - Segment tag to find
/// * `element_index` - Which element contains the qualifier
/// * `qualifier` - Expected qualifier value
/// * `group_path` - Path of group IDs from root
/// * `instance_index` - Which repetition of the innermost group (0-based)
fn find_segments_with_qualifier_in_group(
&self,
segment_id: &str,
element_index: usize,
qualifier: &str,
group_path: &[&str],
instance_index: usize,
) -> Vec<OwnedSegment>;
/// Count repetitions of a group at the given path.
fn group_instance_count(&self, group_path: &[&str]) -> usize;
/// Find all segments with the given tag in one group instance, addressed
/// by the repetition index at *every* level: `[("SG4", 1), ("SG8", 0)]` is
/// the first SG8 of the second SG4.
///
/// [`find_segments_in_group`](Self::find_segments_in_group) indexes only the
/// innermost group, so it cannot reach an SG8 under any SG4 but the first.
/// The default falls back to it; implementations that can address every
/// level override this.
fn find_segments_in_instance(
&self,
segment_id: &str,
path: &[(&str, usize)],
) -> Vec<OwnedSegment> {
let Some(&(_, instance_index)) = path.last() else {
return Vec::new();
};
let group_path: Vec<&str> = path.iter().map(|(id, _)| *id).collect();
self.find_segments_in_group(segment_id, &group_path, instance_index)
}
/// Count the repetitions of `child_group_id` in the group instance at
/// `parent` (addressed at every level, as for
/// [`find_segments_in_instance`](Self::find_segments_in_instance)); an
/// empty `parent` counts the top-level repetitions.
///
/// The default falls back to the innermost-index methods.
fn child_instance_count(&self, parent: &[(&str, usize)], child_group_id: &str) -> usize {
match parent.last() {
None => self.group_instance_count(&[child_group_id]),
Some(&(_, parent_instance)) => {
let parent_path: Vec<&str> = parent.iter().map(|(id, _)| *id).collect();
self.child_group_instance_count(&parent_path, parent_instance, child_group_id)
}
}
}
/// Like [`find_segments_in_instance`](Self::find_segments_in_instance), but
/// including the segments of every group nested in that instance: "in
/// dieser SG8 … SG10 CCI" reads the SG8's SG10s too.
///
/// The default sees the instance's own segments only.
fn find_segments_in_subtree(
&self,
segment_id: &str,
path: &[(&str, usize)],
) -> Vec<OwnedSegment> {
self.find_segments_in_instance(segment_id, path)
}
/// Check if a group instance has any segments at all.
///
/// Returns `true` if the group instance at `instance_index` contains at least
/// one segment. Used to distinguish genuinely populated group instances from
/// navigator implementations that can't resolve per-instance segments.
fn has_any_segment_in_group(&self, _group_path: &[&str], _instance_index: usize) -> bool {
false // Default: unknown, treat as unpopulated
}
/// Check if a group instance belongs to the MIG variant identified by `mig_number`.
///
/// Returns `true` when the instance's variant defines the given `mig_number`
/// (directly or in a nested group). Used to scope per-instance rules — a rule
/// tagged with `mig_number` only applies to instances whose variant includes
/// that number. Example: PID 55218 has two SG8 variants (sg8_z01 with SEQ
/// mig=00115, sg8_z45_z84 with SEQ mig=00171). A `[1P1..n]` package on SEQ
/// mig=00171 must not be checked against sg8_z01 instances.
///
/// Default: `true` (cannot determine — keep old behavior). Implementations
/// backed by an assembled tree should consult `variant_mig_numbers`.
fn instance_has_mig_number(
&self,
_group_path: &[&str],
_instance_index: usize,
_mig_number: &str,
) -> bool {
true
}
/// Count repetitions of a child group within a specific parent group instance.
///
/// * `parent_path` - Path to the parent group (e.g., `&["SG4", "SG8"]`)
/// * `parent_instance` - Which repetition of the parent group (0-based)
/// * `child_group_id` - ID of the child group to count (e.g., `"SG10"`)
fn child_group_instance_count(
&self,
parent_path: &[&str],
parent_instance: usize,
child_group_id: &str,
) -> usize {
let _ = (parent_path, parent_instance, child_group_id);
0
}
/// Find all segments with the given tag within a child group instance.
///
/// * `segment_id` - Segment tag to find (e.g., "CCI")
/// * `parent_path` - Path to the parent group (e.g., `&["SG4", "SG8"]`)
/// * `parent_instance` - Which repetition of the parent group (0-based)
/// * `child_group_id` - ID of the child group (e.g., `"SG10"`)
/// * `child_instance` - Which repetition of the child group (0-based)
fn find_segments_in_child_group(
&self,
segment_id: &str,
parent_path: &[&str],
parent_instance: usize,
child_group_id: &str,
child_instance: usize,
) -> Vec<OwnedSegment> {
let _ = (
segment_id,
parent_path,
parent_instance,
child_group_id,
child_instance,
);
vec![]
}
/// Extract a single value from the first matching segment in a group instance.
///
/// More efficient than `find_segments_in_group` when only one value is needed.
///
/// * `segment_id` - Segment tag to find
/// * `element_index` - Which element to extract from
/// * `component_index` - Which component within the element
/// * `group_path` - Path of group IDs from root
/// * `instance_index` - Which repetition of the innermost group (0-based)
fn extract_value_in_group(
&self,
segment_id: &str,
element_index: usize,
component_index: usize,
group_path: &[&str],
instance_index: usize,
) -> Option<String> {
let _ = (
segment_id,
element_index,
component_index,
group_path,
instance_index,
);
None
}
}