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