Skip to main content

hl7_net/
field.rs

1use crate::component::Component;
2use crate::encoding::HL7Encoding;
3use crate::error::Hl7Error;
4
5/// A field of an HL7 segment. A field is either componentized (a list of
6/// [`Component`]s separated by the component delimiter) or has repetitions
7/// (a list of sub-fields separated by the repetition delimiter).
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Field {
10    raw: String,
11    /// The parsed components (empty for a field that has repetitions).
12    pub components: Vec<Component>,
13    /// The repetitions of this field (empty unless `has_repetitions`).
14    pub repetitions: Vec<Field>,
15    /// `true` when the field is split into more than one component.
16    pub is_componentized: bool,
17    /// `true` when the field contains repetitions.
18    pub has_repetitions: bool,
19    /// `true` for the MSH delimiter-defining fields, whose value is never decoded.
20    pub is_delimiters_field: bool,
21}
22
23impl Field {
24    /// Parses a field from its raw value, handling repetitions and components.
25    pub fn parse(raw: &str, enc: &HL7Encoding) -> Self {
26        if raw.contains(enc.repeat_delimiter) {
27            let repetitions: Vec<Field> = raw
28                .split(enc.repeat_delimiter)
29                .map(|r| Field::parse(r, enc))
30                .collect();
31
32            Self {
33                raw: raw.to_string(),
34                components: Vec::new(),
35                repetitions,
36                is_componentized: false,
37                has_repetitions: true,
38                is_delimiters_field: false,
39            }
40        } else {
41            let components: Vec<Component> = raw
42                .split(enc.component_delimiter)
43                .map(|c| Component::parse(c, enc))
44                .collect();
45            let is_componentized = components.len() > 1;
46
47            Self {
48                raw: raw.to_string(),
49                components,
50                repetitions: Vec::new(),
51                is_componentized,
52                has_repetitions: false,
53                is_delimiters_field: false,
54            }
55        }
56    }
57
58    /// Builds a delimiter-defining field (e.g. MSH-1/MSH-2): its value is stored
59    /// verbatim as a single, unsplit component.
60    pub(crate) fn new_delimiters(raw: &str) -> Self {
61        Self {
62            raw: raw.to_string(),
63            components: vec![Component::single(raw)],
64            repetitions: Vec::new(),
65            is_componentized: false,
66            has_repetitions: false,
67            is_delimiters_field: true,
68        }
69    }
70
71    /// The raw value, or `None` when "present but null".
72    pub fn raw(&self, enc: &HL7Encoding) -> Option<&str> {
73        if self.raw == enc.present_but_null {
74            None
75        } else {
76            Some(&self.raw)
77        }
78    }
79
80    /// The decoded value, or `None` when "present but null".
81    pub fn value(&self, enc: &HL7Encoding) -> Option<String> {
82        if self.raw == enc.present_but_null {
83            None
84        } else {
85            Some(enc.decode(&self.raw))
86        }
87    }
88
89    /// Re-parses the field from a new raw value (preserving the delimiters flag).
90    pub fn set_value(&mut self, value: &str, enc: &HL7Encoding) {
91        if self.is_delimiters_field {
92            *self = Field::new_delimiters(value);
93        } else {
94            *self = Field::parse(value, enc);
95        }
96    }
97
98    /// Returns the component at the given 1-based position.
99    pub fn component(&self, position: usize) -> Result<&Component, Hl7Error> {
100        position
101            .checked_sub(1)
102            .and_then(|i| self.components.get(i))
103            .ok_or_else(|| Hl7Error::new("Component not available"))
104    }
105
106    /// Returns a specific 1-based repetition, if this field has repetitions.
107    pub fn repetition(&self, repetition_number: usize) -> Option<&Field> {
108        if self.has_repetitions {
109            repetition_number.checked_sub(1).and_then(|i| self.repetitions.get(i))
110        } else {
111            None
112        }
113    }
114
115    /// Appends a component to the end of the field.
116    pub fn add_component(&mut self, component: Component) {
117        self.components.push(component);
118    }
119
120    /// Inserts a component at a 1-based position, padding with blank components
121    /// when the position is beyond the current length.
122    pub fn add_component_at(&mut self, component: Component, position: usize, enc: &HL7Encoding) {
123        let index = position.saturating_sub(1);
124
125        if index < self.components.len() {
126            self.components[index] = component;
127        } else {
128            while self.components.len() < index {
129                self.components.push(Component::parse("", enc));
130            }
131            self.components.push(component);
132        }
133    }
134
135    /// Adds a field as a repetition. Requires `has_repetitions` to be set.
136    pub fn add_repeating_field(&mut self, field: Field) -> Result<(), Hl7Error> {
137        if !self.has_repetitions {
138            return Err(Hl7Error::new(
139                "Repeating field must have repetitions (has_repetitions = true)",
140            ));
141        }
142
143        self.repetitions.push(field);
144        Ok(())
145    }
146
147    /// Removes any trailing components whose decoded value is the empty string.
148    pub fn remove_empty_trailing_components(&mut self, enc: &HL7Encoding) {
149        while let Some(last) = self.components.last() {
150            if last.value(enc).as_deref() == Some("") {
151                self.components.pop();
152            } else {
153                break;
154            }
155        }
156    }
157
158    /// Serializes the field (including any repetitions) into `out`.
159    pub fn serialize(&self, out: &mut String, enc: &HL7Encoding) {
160        if self.is_delimiters_field {
161            if let Some(raw) = self.raw(enc) {
162                out.push_str(raw);
163            }
164            return;
165        }
166
167        if self.has_repetitions {
168            for (j, rep) in self.repetitions.iter().enumerate() {
169                if j > 0 {
170                    out.push(enc.repeat_delimiter);
171                }
172                rep.serialize_single(out, enc);
173            }
174        } else {
175            self.serialize_single(out, enc);
176        }
177    }
178
179    /// Serializes a single (non-repeating) field's components and subcomponents.
180    fn serialize_single(&self, out: &mut String, enc: &HL7Encoding) {
181        if self.components.is_empty() {
182            out.push_str(&enc.encode_opt(self.value(enc).as_deref()));
183            return;
184        }
185
186        for (idx, com) in self.components.iter().enumerate() {
187            if idx > 0 {
188                out.push(enc.component_delimiter);
189            }
190
191            if com.sub_components.is_empty() {
192                out.push_str(&enc.encode_opt(com.value(enc).as_deref()));
193            } else {
194                for (i, sub) in com.sub_components.iter().enumerate() {
195                    if i > 0 {
196                        out.push(enc.subcomponent_delimiter);
197                    }
198                    out.push_str(&enc.encode_opt(sub.value(enc).as_deref()));
199                }
200            }
201        }
202    }
203}