hl7_parser/message/
repeat.rs

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