1use super::{fields::Field, separators::Separators, Hl7ParseError};
2use std::fmt::Display;
3use std::ops::Index;
4
5#[derive(Debug, PartialEq, Clone)]
7pub struct Segment<'a> {
8 pub source: &'a str,
9 pub delim: char,
10 pub fields: Vec<Field<'a>>,
11}
12
13impl<'a> Segment<'a> {
14 pub fn parse<S: Into<&'a str>>(
16 input: S,
17 delims: &Separators,
18 ) -> Result<Segment<'a>, Hl7ParseError> {
19 let input = input.into();
20
21 let fields: Result<Vec<Field<'a>>, Hl7ParseError> = input
22 .split(delims.field)
23 .map(|line| Field::parse(line, delims))
24 .collect();
25
26 let fields = fields?;
27 let seg = Segment {
28 source: input,
29 delim: delims.segment,
30 fields,
31 };
32 Ok(seg)
33 }
34
35 #[inline]
37 pub fn as_str(&self) -> &'a str {
38 self.source
39 }
40
41 pub fn query<'b, S>(&self, fidx: S) -> &'a str
43 where
44 S: Into<&'b str>,
45 {
46 let fidx = fidx.into();
47 let sections = fidx.split('.').collect::<Vec<&str>>();
48
49 match sections.len() {
50 1 => {
51 let stringnum = sections[0]
52 .chars()
53 .filter(|c| c.is_digit(10))
54 .collect::<String>();
55 let idx: usize = stringnum.parse().unwrap();
56 self[idx]
57 }
58 _ => {
59 let stringnum = sections[0]
60 .chars()
61 .filter(|c| c.is_digit(10))
62 .collect::<String>();
63 let idx: usize = stringnum.parse().unwrap();
64 if idx > self.fields.len() - 1 {
65 return "";
66 }
67 let field = &self.fields[idx];
68 let query = sections[1..].join(".");
69
70 field.query(&*query)
71 }
72 }
73 }
74}
75
76impl<'a> Display for Segment<'a> {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 write!(f, "{}", self.source)
80 }
81}
82
83impl<'a> Index<usize> for Segment<'a> {
84 type Output = &'a str;
85 fn index(&self, fidx: usize) -> &Self::Output {
87 if fidx > self.fields.len() - 1 {
88 return &"";
89 };
90 &self.fields[fidx].source
91 }
92}
93
94impl<'a> Index<(usize, usize)> for Segment<'a> {
95 type Output = &'a str;
96 fn index(&self, fidx: (usize, usize)) -> &Self::Output {
98 if fidx.0 > self.fields.len() - 1 || fidx.1 > self.fields[fidx.0].components.len() - 1 {
99 return &"";
100 }
101 &self.fields[fidx.0][fidx.1]
102 }
103}
104
105impl<'a> Index<(usize, usize, usize)> for Segment<'a> {
106 type Output = &'a str;
107 fn index(&self, fidx: (usize, usize, usize)) -> &Self::Output {
109 if fidx.0 > self.fields.len() - 1
110 || fidx.1 > self.fields[fidx.0].components.len() - 1
111 || fidx.2 > self.fields[fidx.0].subcomponents[fidx.1].len() - 1
112 {
113 return &"";
114 }
115 &self.fields[fidx.0][(fidx.1, fidx.2)]
116 }
117}
118
119#[cfg(feature = "string_index")]
120impl<'a> Index<&str> for Segment<'a> {
121 type Output = &'a str;
122 #[cfg(feature = "string_index")]
124 fn index(&self, fidx: &str) -> &Self::Output {
125 let sections = fidx.split('.').collect::<Vec<&str>>();
126 let stringnum = sections[0]
127 .chars()
128 .filter(|c| c.is_digit(10))
129 .collect::<String>();
130 let mut idx: usize = stringnum.parse().unwrap();
131 if self.fields[0].source == "MSH" {
135 if idx == 1 {
136 return &"|";
138 } else {
139 idx = idx - 1
140 }
141 }
142 match sections.len() {
143 1 => &self[idx],
144 _ => {
145 if idx < self.fields.len() {
146 &self.fields[idx][sections[1..].join(".")]
147 } else {
148 &""
149 }
150 }
151 }
152 }
153}
154
155#[cfg(feature = "string_index")]
156impl<'a> Index<String> for Segment<'a> {
157 type Output = &'a str;
158
159 #[cfg(feature = "string_index")]
161 fn index(&self, idx: String) -> &Self::Output {
162 &self[idx.as_str()]
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use crate::{message::Message, segments::*, separators::Separators, Hl7ParseError};
169 use std::convert::TryFrom;
170
171 #[test]
172 fn ensure_numeric_index() {
173 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment^sub&segment";
174 let msg = Message::try_from(hl7).unwrap();
175 let x = &msg.segments[1];
176 let (f, c, s) = (x[1], x[(1, 0)], x[(1, 0, 1)]);
177 assert_eq!(f, "segment^sub&segment");
178 assert_eq!(c, f);
179 assert_eq!(s, "sub&segment");
180 }
181
182 #[test]
183 fn ensure_string_query() {
184 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment^sub&segment";
185 let msg = Message::try_from(hl7).unwrap();
186 let x = &msg.segments[1];
187 let (f, c, s, oob) = (
188 x.query("F1"), x.query("F1.R1"), x.query(&*String::from("F1.R1.C1")), String::from(x.query("F10")) + x.query("F1.R10") + x.query("F1.R2.C10"),
192 );
193 assert_eq!(f, "segment^sub&segment");
194 assert_eq!(c, f);
195 assert_eq!(s, "segment");
196 assert_eq!(oob, "");
197 }
198
199 #[cfg(feature = "string_index")]
200 mod string_index_tests {
201 use super::*;
202 #[test]
203 fn ensure_string_index() {
204 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment^sub&segment";
205 let msg = Message::try_from(hl7).unwrap();
206 let x = &msg.segments[1];
207 let (f, c, s, oob) = (
208 x["F1"], x["F1.R1"], x["F1.R1.C1".to_owned()], x["F1.R2.C2"],
212 );
213 assert_eq!(f, "segment^sub&segment");
214 assert_eq!(c, "segment^sub&segment");
215 assert_eq!(s, "segment");
216 assert_eq!(oob, "");
217 }
218 }
219}