use super::{fields::Field, separators::Separators, Hl7ParseError};
use std::fmt::Display;
use std::ops::Index;
#[derive(Debug, PartialEq, Clone)]
pub struct Segment<'a> {
pub source: &'a str,
pub delim: char,
pub fields: Vec<Field<'a>>,
}
impl<'a> Segment<'a> {
pub fn parse<S: Into<&'a str>>(
input: S,
delims: &Separators,
) -> Result<Segment<'a>, Hl7ParseError> {
let input = input.into();
let fields: Result<Vec<Field<'a>>, Hl7ParseError> = input
.split(delims.field)
.map(|line| Field::parse(line, delims))
.collect();
let fields = fields?;
let seg = Segment {
source: input,
delim: delims.segment,
fields,
};
Ok(seg)
}
#[inline]
pub fn as_str(&self) -> &'a str {
self.source
}
pub fn query<'b, S>(&self, fidx: S) -> &'a str
where
S: Into<&'b str>,
{
let fidx = fidx.into();
let sections = fidx.split('.').collect::<Vec<&str>>();
match sections.len() {
1 => {
let stringnum = sections[0]
.chars()
.filter(|c| c.is_digit(10))
.collect::<String>();
let idx: usize = stringnum.parse().unwrap();
self[idx]
}
_ => {
let stringnum = sections[0]
.chars()
.filter(|c| c.is_digit(10))
.collect::<String>();
let idx: usize = stringnum.parse().unwrap();
if idx > self.fields.len() - 1 {
return "";
}
let field = &self.fields[idx];
let query = sections[1..].join(".");
field.query(&*query)
}
}
}
}
impl<'a> Display for Segment<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.source)
}
}
impl<'a> Index<usize> for Segment<'a> {
type Output = &'a str;
fn index(&self, fidx: usize) -> &Self::Output {
if fidx > self.fields.len() - 1 {
return &"";
};
&self.fields[fidx].source
}
}
impl<'a> Index<(usize, usize)> for Segment<'a> {
type Output = &'a str;
fn index(&self, fidx: (usize, usize)) -> &Self::Output {
if fidx.0 > self.fields.len() - 1 || fidx.1 > self.fields[fidx.0].components.len() - 1 {
return &"";
}
&self.fields[fidx.0][fidx.1]
}
}
impl<'a> Index<(usize, usize, usize)> for Segment<'a> {
type Output = &'a str;
fn index(&self, fidx: (usize, usize, usize)) -> &Self::Output {
if fidx.0 > self.fields.len() - 1
|| fidx.1 > self.fields[fidx.0].components.len() - 1
|| fidx.2 > self.fields[fidx.0].subcomponents[fidx.1].len() - 1
{
return &"";
}
&self.fields[fidx.0][(fidx.1, fidx.2)]
}
}
#[cfg(feature = "string_index")]
impl<'a> Index<&str> for Segment<'a> {
type Output = &'a str;
#[cfg(feature = "string_index")]
fn index(&self, fidx: &str) -> &Self::Output {
let sections = fidx.split('.').collect::<Vec<&str>>();
let stringnum = sections[0]
.chars()
.filter(|c| c.is_digit(10))
.collect::<String>();
let mut idx: usize = stringnum.parse().unwrap();
if self.fields[0].source == "MSH" {
if idx == 1 {
return &"|";
} else {
idx = idx - 1
}
}
match sections.len() {
1 => &self[idx],
_ => {
if idx < self.fields.len() {
&self.fields[idx][sections[1..].join(".")]
} else {
&""
}
}
}
}
}
#[cfg(feature = "string_index")]
impl<'a> Index<String> for Segment<'a> {
type Output = &'a str;
#[cfg(feature = "string_index")]
fn index(&self, idx: String) -> &Self::Output {
&self[idx.as_str()]
}
}
#[cfg(test)]
mod tests {
use crate::{message::Message, segments::*, separators::Separators, Hl7ParseError};
use std::convert::TryFrom;
#[test]
fn ensure_numeric_index() {
let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment^sub&segment";
let msg = Message::try_from(hl7).unwrap();
let x = &msg.segments[1];
let (f, c, s) = (x[1], x[(1, 0)], x[(1, 0, 1)]);
assert_eq!(f, "segment^sub&segment");
assert_eq!(c, f);
assert_eq!(s, "sub&segment");
}
#[test]
fn ensure_string_query() {
let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment^sub&segment";
let msg = Message::try_from(hl7).unwrap();
let x = &msg.segments[1];
let (f, c, s, oob) = (
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"),
);
assert_eq!(f, "segment^sub&segment");
assert_eq!(c, f);
assert_eq!(s, "segment");
assert_eq!(oob, "");
}
#[cfg(feature = "string_index")]
mod string_index_tests {
use super::*;
#[test]
fn ensure_string_index() {
let hl7 = "MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rOBR|segment^sub&segment";
let msg = Message::try_from(hl7).unwrap();
let x = &msg.segments[1];
let (f, c, s, oob) = (
x["F1"], x["F1.R1"], x["F1.R1.C1".to_owned()], x["F1.R2.C2"],
);
assert_eq!(f, "segment^sub&segment");
assert_eq!(c, "segment^sub&segment");
assert_eq!(s, "segment");
assert_eq!(oob, "");
}
}
}