1use super::segments::Segment;
2use super::separators::Separators;
3use super::*;
4use std::convert::TryFrom;
5use std::fmt::Display;
6use std::ops::Index;
7
8#[derive(Debug, PartialEq)]
12pub struct Message<'a> {
13 pub source: &'a str,
14 pub segments: Vec<Segment<'a>>,
15 separators: Separators,
16}
17
18impl<'a> Message<'a> {
19 pub fn new(source: &'a str) -> Message<'a> {
20 let separators = str::parse::<Separators>(source).unwrap();
21 let segments: Vec<Segment<'a>> = source
22 .split(separators.segment)
23 .map(|line| Segment::parse(line, &separators).unwrap())
24 .collect();
25
26 Message {
27 source,
28 segments,
29 separators,
30 }
31 }
32
33 pub fn segments_by_name(&self, name: &str) -> Result<Vec<&Segment<'a>>, Hl7ParseError> {
35 let found: Vec<&Segment<'a>> = self
36 .segments
37 .iter()
38 .filter(|s| s.fields[0].source == name)
39 .collect();
40 Ok(found)
41 }
42
43 pub fn segments_to_str_vecs(
45 segments: Vec<&Segment<'a>>,
46 ) -> Result<Vec<Vec<&'a str>>, Hl7ParseError> {
47 let vecs = segments
48 .iter()
49 .map(|s| s.fields.iter().map(|f| f.value()).collect())
50 .collect();
51 Ok(vecs)
52 }
53
54 #[inline]
68 pub fn as_str(&self) -> &'a str {
69 self.source
70 }
71
72 pub fn get_separators(&self) -> Separators {
74 self.separators
75 }
76
77 pub fn query<'b, S>(&self, idx: S) -> &'a str
79 where
80 S: Into<&'b str>,
81 {
82 let idx = idx.into();
83
84 let indices = Self::parse_query_string(idx);
86 let seg_name = indices[0];
87 let seg_index = self
89 .segments
90 .iter()
91 .position(|r| &r.as_str()[..seg_name.len()] == seg_name)
92 .expect("Segment not found");
93 let seg = &self.segments[seg_index];
94 if indices.len() < 2 {
95 seg.source
96 } else {
97 let query = indices[1..].join(".");
98 seg.query(&*query)
99 }
100 }
101
102 pub fn parse_query_string(query: &str) -> Vec<&str> {
106 fn query_idx_pos(indices: &[&str], idx: &str) -> Option<usize> {
107 indices[1..]
108 .iter()
109 .position(|r| r[0..1].to_uppercase() == idx)
110 }
111 let indices: Vec<&str> = query.split('.').collect();
112 let mut res = vec![indices[0]];
114 let sub_pos = query_idx_pos(&indices, "S");
116 let com_pos = query_idx_pos(&indices, "C");
117 let rep_pos = query_idx_pos(&indices, "R");
118 let fld_pos = query_idx_pos(&indices, "F");
119 match fld_pos {
121 Some(f) => res.push(indices[f + 1]),
122 None => {
123 if rep_pos.is_some() || com_pos.is_some() || sub_pos.is_some() {
125 res.push("F1")
126 } else {
127 return res;
128 }
129 }
130 };
131 match rep_pos {
132 Some(r) => res.push(indices[r + 1]),
133 None => {
134 if com_pos.is_some() || sub_pos.is_some() {
136 res.push("R1")
137 } else {
138 return res;
139 }
140 }
141 };
142 match com_pos {
143 Some(c) => res.push(indices[c + 1]),
144 None => {
145 if sub_pos.is_some() {
147 res.push("C1")
148 } else {
149 return res;
150 }
151 }
152 };
153 if let Some(s) = sub_pos {
154 res.push(indices[s + 1])
155 }
156 res
157 }
158}
159
160impl<'a> TryFrom<&'a str> for Message<'a> {
161 type Error = Hl7ParseError;
162
163 fn try_from(source: &'a str) -> Result<Self, Self::Error> {
166 let delimiters = str::parse::<Separators>(source)?;
167
168 let segments: Result<Vec<Segment<'a>>, Hl7ParseError> = source
169 .split(delimiters.segment)
170 .map(|line| Segment::parse(line, &delimiters))
171 .collect();
172
173 let msg = Message {
174 source,
175 segments: segments?,
176 separators: delimiters,
177 };
178
179 Ok(msg)
180 }
181}
182
183impl<'a> Display for Message<'a> {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 write!(f, "{}", self.source)
186 }
187}
188
189impl<'a> Clone for Message<'a> {
190 fn clone(&self) -> Self {
203 Message::try_from(self.source).unwrap()
204 }
205}
206
207impl<'a> Index<usize> for Message<'a> {
208 type Output = &'a str;
209
210 fn index(&self, idx: usize) -> &Self::Output {
212 if idx > self.segments.len() {
213 return &"";
214 }
215 &self.segments[idx].source
216 }
217}
218#[cfg(feature = "string_index")]
219impl<'a> Index<String> for Message<'a> {
220 type Output = &'a str;
221
222 #[cfg(feature = "string_index")]
224 fn index(&self, idx: String) -> &Self::Output {
225 let indices = Self::parse_query_string(&idx);
227 let seg_name = indices[0];
228 let seg_index = self
230 .segments
231 .iter()
232 .position(|r| &r.as_str()[..seg_name.len()] == seg_name)
233 .expect("Segment not found");
234 let seg = &self.segments[seg_index];
235 if indices.len() < 2 {
236 &seg.source
237 } else {
238 &seg[indices[1..].join(".")]
239 }
240 }
241}
242
243#[cfg(feature = "string_index")]
244impl<'a> Index<&str> for Message<'a> {
245 type Output = &'a str;
246
247 #[cfg(feature = "string_index")]
248 fn index(&self, idx: &str) -> &Self::Output {
249 &self[String::from(idx)]
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[test]
258 fn ensure_segments_are_returned() -> Result<(), Hl7ParseError> {
259 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment";
260 let msg = Message::try_from(hl7)?;
261
262 assert_eq!(msg.segments.len(), 2);
263 Ok(())
264 }
265
266 #[test]
267 fn ensure_segments_are_found() -> Result<(), Hl7ParseError> {
268 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment";
269 let msg = Message::try_from(hl7)?;
270
271 assert_eq!(msg.segments_by_name("OBR").unwrap().len(), 1);
272 Ok(())
273 }
274
275 #[test]
276 fn ensure_segments_convert_to_vectors() -> Result<(), Hl7ParseError> {
277 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment";
278 let msg = Message::try_from(hl7)?;
279 let segs = msg.segments_by_name("OBR")?;
280 let sval = segs.first().unwrap().fields.first().unwrap().value();
281 let vecs = Message::segments_to_str_vecs(segs).unwrap();
282 let vval = vecs.first().unwrap().first().unwrap();
283
284 assert_eq!(vval, &sval);
285 Ok(())
286 }
287 #[test]
288 fn ensure_clones_are_owned() -> Result<(), Hl7ParseError> {
289 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment";
290 let msg = Message::try_from(hl7)?;
291 let dolly = msg.clone();
293 let dolly = dolly.to_owned();
294 assert_eq!(msg.query("MSH.F7"), dolly.query("MSH.F7"));
295 Ok(())
296 }
297
298 #[test]
299 fn ensure_to_string() -> Result<(), Hl7ParseError> {
300 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment";
301 let msg = Message::try_from(hl7)?;
302 assert_eq!(msg.to_string(), String::from(hl7));
303 Ok(())
304 }
305
306 #[test]
307 fn ensure_message_creation() -> Result<(), Hl7ParseError> {
308 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment";
309 let msg0 = Message::try_from(hl7)?;
310 let msg1 = Message::new(hl7);
311
312 assert_eq!(msg0, msg1);
313 Ok(())
314 }
315
316 #[test]
317 fn ensure_query() -> Result<(), Hl7ParseError> {
318 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment^sub&segment";
319 let msg = Message::try_from(hl7)?;
320 assert_eq!(msg.query("OBR.F1.R1.C2"), "sub&segment");
321 assert_eq!(msg.query(&*"OBR.F1.R1.C1".to_string()), "segment"); assert_eq!(msg.query(&*String::from("OBR.F1.R1.C1")), "segment");
323 assert_eq!(msg.query("MSH.F1"), "^~\\&");
324 Ok(())
325 }
326
327 #[cfg(feature = "string_index")]
328 mod string_index_tests {
329 use super::*;
330 #[test]
331 fn ensure_index() -> Result<(), Hl7ParseError> {
332 let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment^sub&segment";
333 let msg = Message::try_from(hl7)?;
334 assert_eq!(msg["OBR.F1.R1.C2"], "sub&segment");
335 assert_eq!(msg[&*"OBR.F1.R1.C1".to_string()], "segment"); assert_eq!(msg[String::from("OBR.F1.R1.C1")], "segment");
337 assert_eq!(msg[String::from("OBR.F1.C1")], "segment"); assert_eq!(msg[String::from("OBR.F1.R1.C2.S1")], "sub");
339 println!("{}", Message::parse_query_string("MSH.F2").join("."));
340 assert_eq!(msg["MSH.F2"], "^~\\&");
341 Ok(())
342 }
343 }
344}