hl7_parser/message/
field.rs

1use crate::display::FieldDisplay;
2
3use super::Repeat;
4use std::ops::Range;
5
6/// A field in an HL7 message. A field is a collection of repeats, separated by the repeat
7/// separator character. Fields are separated by the field separator character.
8#[derive(Debug, Clone, PartialEq, Eq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize))]
10pub struct Field<'m> {
11    pub(crate) source: &'m str,
12    pub repeats: Vec<Repeat<'m>>,
13    pub range: Range<usize>,
14}
15
16impl<'m> Field<'m> {
17    pub(crate) fn new_single(source: &'m str, range: Range<usize>) -> Self {
18        Field {
19            source,
20            repeats: vec![Repeat::new_single(source, range.clone())],
21            range,
22        }
23    }
24
25    #[inline]
26    /// An iterator over the repeats of the field
27    pub fn repeats(&self) -> impl Iterator<Item = &Repeat<'m>> {
28        self.repeats.iter()
29    }
30
31    #[inline]
32    /// Display the field value, using the separators to decode escape sequences
33    /// by default. Note: if you want to display the raw value without decoding escape
34    /// sequences, use the `#` flag, e.g. `format!("{:#}", field.display(separators))`.
35    /// Repeats will be separated by the repeat separator character.
36    /// Fields will be separated by the field separator character.
37    /// Components will be separated by the component separator character.
38    /// Subcomponents will be separated by the subcomponent separator character.
39    pub fn display(&'m self, separators: &'m super::Separators) -> FieldDisplay<'m> {
40        FieldDisplay {
41            repeats: &self.repeats,
42            separators,
43        }
44    }
45
46    #[inline]
47    /// Get the raw value of the field. This is the value as it appears in the message,
48    /// without any decoding of escape sequences, and including all repeats and
49    /// their separators.
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// let field = hl7_parser::parser::parse_field("foo~bar").unwrap();
55    /// assert_eq!(field.repeats.len(), 2);
56    /// assert_eq!(field.raw_value(), "foo~bar");
57    /// ```
58    pub fn raw_value(&self) -> &'m str {
59        self.source
60    }
61
62    #[inline]
63    /// Returns true if the field has more than one repeat. Note that
64    /// if the field has only one repeat, the value of that repeat
65    /// is essentially the value of the field, so the value of the field
66    /// can be obtained using `raw_value()`.
67    ///
68    /// # Examples
69    ///
70    /// ```
71    /// let field = hl7_parser::parser::parse_field("foo~bar").unwrap();
72    /// assert_eq!(field.has_repeats(), true);
73    /// let field = hl7_parser::parser::parse_field("foo").unwrap();
74    /// assert_eq!(field.has_repeats(), false);
75    /// let field = hl7_parser::parser::parse_field("foo^bar").unwrap();
76    /// assert_eq!(field.has_repeats(), false);
77    /// ```
78    pub fn has_repeats(&self) -> bool {
79        self.repeats.len() > 1
80    }
81
82    /// Returns true if the field has no repeats, or if all repeats
83    /// have empty values.
84    ///
85    /// # Examples
86    ///
87    /// ```
88    /// let field = hl7_parser::parser::parse_field("foo~bar").unwrap();
89    /// assert_eq!(field.is_empty(), false);
90    /// let field = hl7_parser::parser::parse_field("").unwrap();
91    /// assert_eq!(field.is_empty(), true);
92    /// let field = hl7_parser::parser::parse_field("~").unwrap();
93    /// assert_eq!(field.is_empty(), true);
94    /// ```
95    pub fn is_empty(&self) -> bool {
96        self.repeats.is_empty() || self.repeats.iter().all(|r| r.is_empty())
97    }
98
99    /// Get the repeat at the specified 1-based index
100    /// Returns None if the index is out of bounds
101    ///
102    /// # Examples
103    ///
104    /// ```
105    /// let field = hl7_parser::parser::parse_field("foo~bar").unwrap();
106    /// assert_eq!(field.repeat(1).unwrap().raw_value(), "foo");
107    /// assert_eq!(field.repeat(2).unwrap().raw_value(), "bar");
108    /// assert_eq!(field.repeat(3), None);
109    /// ```
110    pub fn repeat(&self, number: usize) -> Option<&Repeat<'m>> {
111        debug_assert!(number > 0, "Repeat numbers are 1-indexed");
112        self.repeats.get(number - 1)
113    }
114
115    /// Get the component at the specified 1-based index
116    /// Returns None if the index is out of bounds
117    /// If the field has multiple repeats, the component will be taken from the first repeat
118    /// only.
119    /// If the field has no repeats, this will return None.
120    /// If the field has one or more repeats, this is equivalent to calling
121    /// `repeat(1).component(number)`.
122    ///
123    /// This is a convenience method for the common case where a field has only one repeat.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// let field = hl7_parser::parser::parse_field("foo^bar~baz^qux").unwrap();
129    /// assert_eq!(field.component(1).unwrap().raw_value(), "foo");
130    /// assert_eq!(field.component(2).unwrap().raw_value(), "bar");
131    /// assert_eq!(field.component(3), None);
132    /// ```
133    pub fn component(&self, number: usize) -> Option<&super::Component<'m>> {
134        debug_assert!(number > 0, "Component numbers are 1-indexed");
135        self.repeats.first().and_then(|r| r.component(number))
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use crate::message::{Component, Separators, Subcomponent};
143
144    #[test]
145    fn fields_can_display() {
146        let separators = Separators::default();
147
148        let repeat = Repeat {
149            source: r"foo\F\bar",
150            components: vec![Component {
151                source: r"foo\F\bar",
152                subcomponents: vec![Subcomponent {
153                    value: r"foo\F\bar",
154                    range: 0..1, // ignore
155                }],
156                range: 0..1, // ignore
157            }],
158            range: 0..1, // ignore
159        };
160
161        let field = Field {
162            source: r"foo\F\bar~foo\F\bar",
163            repeats: vec![repeat.clone(), repeat],
164            range: 0..1, // ignore
165        };
166
167        assert_eq!(format!("{}", field.display(&separators)), "foo|bar~foo|bar");
168        assert_eq!(
169            format!("{:#}", field.display(&separators)),
170            r"foo\F\bar~foo\F\bar"
171        );
172    }
173}