hl7_parser/parser/
segment.rs1use super::{field::field, Span};
2use crate::message::{Segment, Separators};
3use nom::{
4 bytes::complete::take_while_m_n, character::complete::char, combinator::consumed,
5 multi::separated_list0, sequence::separated_pair, IResult,
6};
7
8pub fn segment<'i>(seps: Separators) -> impl FnMut(Span<'i>) -> IResult<Span<'i>, Segment<'i>> {
9 move |i| parse_segment(i, seps)
10}
11
12fn segment_name<'i>() -> impl FnMut(Span<'i>) -> IResult<Span<'i>, Span<'i>> {
13 move |i| parse_segment_name(i)
14}
15
16pub(crate) fn parse_segment_name(i: Span) -> IResult<Span, Span> {
17 take_while_m_n(3, 3, |c: char| c.is_alphanumeric())(i)
18}
19
20fn parse_segment(i: Span<'_>, seps: Separators) -> IResult<Span<'_>, Segment<'_>> {
21 let pos_start = i.offset;
22 let (i, (segment_src, (name, v))) = consumed(separated_pair(
23 segment_name(),
24 char(seps.field),
25 separated_list0(char(seps.field), field(seps)),
26 ))(i)?;
27 let pos_end = i.offset;
28
29 Ok((
30 i,
31 Segment {
32 source: segment_src.input,
33 name: name.input,
34 fields: v,
35 range: pos_start..pos_end,
36 },
37 ))
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use crate::message::Separators;
44 use pretty_assertions_sorted::assert_eq;
45
46 #[test]
47 fn can_parse_segment() {
48 let separators = Separators::default();
49
50 let input = Span::new("MSH|foo|bar|baz");
51 let actual = parse_segment(input, separators).unwrap().1;
52 assert_eq!(actual.name, "MSH");
53 assert_eq!(actual.fields.len(), 3);
54 assert_eq!(format!("{}", actual.fields[0].display(&separators)), "foo");
55 }
56
57 #[test]
58 fn can_parse_segment_with_number() {
59 let separators = Separators::default();
60
61 let input = Span::new("DB1|foo|bar|baz");
62 let actual = parse_segment(input, separators).unwrap().1;
63 assert_eq!(actual.name, "DB1");
64 assert_eq!(actual.fields.len(), 3);
65 assert_eq!(format!("{}", actual.fields[0].display(&separators)), "foo");
66 }
67
68 #[test]
69 fn cant_parse_segments_with_invalid_names() {
70 let separators = Separators::default();
71
72 let input = Span::new("MS|foo|bar|baz");
73 let actual = parse_segment(input, separators);
74 assert!(actual.is_err());
75
76 let input = Span::new("MSAX|foo|bar|baz");
77 let actual = parse_segment(input, separators);
78 assert!(actual.is_err());
79 }
80
81 #[test]
82 fn cant_parse_segments_with_no_names() {
83 let separators = Separators::default();
84
85 let input = Span::new("|foo|bar|baz");
86 let actual = parse_segment(input, separators);
87 assert!(actual.is_err());
88 }
89
90 #[test]
91 fn cant_parse_segments_with_no_fields() {
92 let separators = Separators::default();
93
94 let input = Span::new("MSH");
95 let actual = parse_segment(input, separators);
96 assert!(actual.is_err());
97 }
98
99 #[test]
100 fn can_parse_segment_with_repeats_components_and_subcomponents() {
101 let separators = Separators::default();
102
103 let input = Span::new(r"MSH|foo^b\R\ar^baz&x~qux^quux^quuz|asdf|");
104 let actual = parse_segment(input, separators).unwrap().1;
105 assert_eq!(actual.name, "MSH");
107 assert_eq!(actual.fields.len(), 3);
108 assert_eq!(
109 actual.fields[0].raw_value(),
110 r"foo^b\R\ar^baz&x~qux^quux^quuz"
111 );
112 assert_eq!(actual.fields[0].repeats.len(), 2);
113 assert_eq!(actual.fields[0].repeats[0].raw_value(), r"foo^b\R\ar^baz&x");
114 assert_eq!(actual.fields[0].repeats[1].raw_value(), r"qux^quux^quuz");
115 assert_eq!(actual.fields[0].repeats[0].components.len(), 3);
116 assert_eq!(actual.fields[0].repeats[0].components[0].raw_value(), "foo");
117 assert_eq!(
118 actual.fields[0].repeats[0].components[1].raw_value(),
119 r"b\R\ar"
120 );
121 assert_eq!(
122 actual.fields[0].repeats[0].components[2].raw_value(),
123 "baz&x"
124 );
125 assert_eq!(
126 actual.fields[0].repeats[0].components[2]
127 .subcomponents
128 .len(),
129 2
130 );
131 assert_eq!(
132 actual.fields[0].repeats[0].components[2].subcomponents[0].raw_value(),
133 "baz"
134 );
135 assert_eq!(
136 actual.fields[0].repeats[0].components[2].subcomponents[1].raw_value(),
137 "x"
138 );
139 }
140
141 #[test]
142 fn can_parse_segment_with_trailing_empty_fields() {
143 let separators = Separators::default();
144
145 let input = Span::new("MSH|foo|bar|baz||");
146 let actual = parse_segment(input, separators).unwrap().1;
147 assert_eq!(actual.fields.len(), 5);
148 assert_eq!(actual.fields[3].raw_value(), "");
149 assert_eq!(actual.fields[4].raw_value(), "");
150 }
151}