hl7_parser/parser/
segment.rs

1use 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        // dbg!(&actual);
106        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}