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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
use crate::component::Component;
use crate::encoding::HL7Encoding;
use crate::error::Hl7Error;
/// A field of an HL7 segment. A field is either componentized (a list of
/// [`Component`]s separated by the component delimiter) or has repetitions
/// (a list of sub-fields separated by the repetition delimiter).
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
raw: String,
/// The parsed components (empty for a field that has repetitions).
pub components: Vec<Component>,
/// The repetitions of this field (empty unless `has_repetitions`).
pub repetitions: Vec<Field>,
/// `true` when the field is split into more than one component.
pub is_componentized: bool,
/// `true` when the field contains repetitions.
pub has_repetitions: bool,
/// `true` for the MSH delimiter-defining fields, whose value is never decoded.
pub is_delimiters_field: bool,
}
impl Field {
/// Parses a field from its raw value, handling repetitions and components.
pub fn parse(raw: &str, enc: &HL7Encoding) -> Self {
if raw.contains(enc.repeat_delimiter) {
let repetitions: Vec<Field> = raw
.split(enc.repeat_delimiter)
.map(|r| Field::parse(r, enc))
.collect();
Self {
raw: raw.to_string(),
components: Vec::new(),
repetitions,
is_componentized: false,
has_repetitions: true,
is_delimiters_field: false,
}
} else {
let components: Vec<Component> = raw
.split(enc.component_delimiter)
.map(|c| Component::parse(c, enc))
.collect();
let is_componentized = components.len() > 1;
Self {
raw: raw.to_string(),
components,
repetitions: Vec::new(),
is_componentized,
has_repetitions: false,
is_delimiters_field: false,
}
}
}
/// Builds a delimiter-defining field (e.g. MSH-1/MSH-2): its value is stored
/// verbatim as a single, unsplit component.
pub(crate) fn new_delimiters(raw: &str) -> Self {
Self {
raw: raw.to_string(),
components: vec![Component::single(raw)],
repetitions: Vec::new(),
is_componentized: false,
has_repetitions: false,
is_delimiters_field: true,
}
}
/// The raw value, or `None` when "present but null".
pub fn raw(&self, enc: &HL7Encoding) -> Option<&str> {
if self.raw == enc.present_but_null {
None
} else {
Some(&self.raw)
}
}
/// The decoded value, or `None` when "present but null".
pub fn value(&self, enc: &HL7Encoding) -> Option<String> {
if self.raw == enc.present_but_null {
None
} else {
Some(enc.decode(&self.raw))
}
}
/// Re-parses the field from a new raw value (preserving the delimiters flag).
pub fn set_value(&mut self, value: &str, enc: &HL7Encoding) {
if self.is_delimiters_field {
*self = Field::new_delimiters(value);
} else {
*self = Field::parse(value, enc);
}
}
/// Returns the component at the given 1-based position.
pub fn component(&self, position: usize) -> Result<&Component, Hl7Error> {
position
.checked_sub(1)
.and_then(|i| self.components.get(i))
.ok_or_else(|| Hl7Error::new("Component not available"))
}
/// Returns a specific 1-based repetition, if this field has repetitions.
pub fn repetition(&self, repetition_number: usize) -> Option<&Field> {
if self.has_repetitions {
repetition_number.checked_sub(1).and_then(|i| self.repetitions.get(i))
} else {
None
}
}
/// Appends a component to the end of the field.
pub fn add_component(&mut self, component: Component) {
self.components.push(component);
}
/// Inserts a component at a 1-based position, padding with blank components
/// when the position is beyond the current length.
pub fn add_component_at(&mut self, component: Component, position: usize, enc: &HL7Encoding) {
let index = position.saturating_sub(1);
if index < self.components.len() {
self.components[index] = component;
} else {
while self.components.len() < index {
self.components.push(Component::parse("", enc));
}
self.components.push(component);
}
}
/// Adds a field as a repetition. Requires `has_repetitions` to be set.
pub fn add_repeating_field(&mut self, field: Field) -> Result<(), Hl7Error> {
if !self.has_repetitions {
return Err(Hl7Error::new(
"Repeating field must have repetitions (has_repetitions = true)",
));
}
self.repetitions.push(field);
Ok(())
}
/// Removes any trailing components whose decoded value is the empty string.
pub fn remove_empty_trailing_components(&mut self, enc: &HL7Encoding) {
while let Some(last) = self.components.last() {
if last.value(enc).as_deref() == Some("") {
self.components.pop();
} else {
break;
}
}
}
/// Serializes the field (including any repetitions) into `out`.
pub fn serialize(&self, out: &mut String, enc: &HL7Encoding) {
if self.is_delimiters_field {
if let Some(raw) = self.raw(enc) {
out.push_str(raw);
}
return;
}
if self.has_repetitions {
for (j, rep) in self.repetitions.iter().enumerate() {
if j > 0 {
out.push(enc.repeat_delimiter);
}
rep.serialize_single(out, enc);
}
} else {
self.serialize_single(out, enc);
}
}
/// Serializes a single (non-repeating) field's components and subcomponents.
fn serialize_single(&self, out: &mut String, enc: &HL7Encoding) {
if self.components.is_empty() {
out.push_str(&enc.encode_opt(self.value(enc).as_deref()));
return;
}
for (idx, com) in self.components.iter().enumerate() {
if idx > 0 {
out.push(enc.component_delimiter);
}
if com.sub_components.is_empty() {
out.push_str(&enc.encode_opt(com.value(enc).as_deref()));
} else {
for (i, sub) in com.sub_components.iter().enumerate() {
if i > 0 {
out.push(enc.subcomponent_delimiter);
}
out.push_str(&enc.encode_opt(sub.value(enc).as_deref()));
}
}
}
}
}