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}