#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Ii {
pub root: String,
pub extension: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Cd {
pub code: String,
pub code_system: Option<String>,
pub display_name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Ivl {
pub value: Option<String>,
pub low: Option<String>,
pub high: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Pq {
pub value: Option<String>,
pub unit: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Ed {
pub media_type: Option<String>,
pub representation: Option<String>,
pub text: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NullFlavor {
NoInformation,
Unknown,
AskedButUnknown,
NotAsked,
TemporarilyUnavailable,
NotApplicable,
Other,
Unrecognized(String),
}
impl NullFlavor {
#[must_use]
pub fn parse(code: &str) -> NullFlavor {
match code {
"NI" => NullFlavor::NoInformation,
"UNK" => NullFlavor::Unknown,
"ASKU" => NullFlavor::AskedButUnknown,
"NASK" => NullFlavor::NotAsked,
"NAV" => NullFlavor::TemporarilyUnavailable,
"NA" => NullFlavor::NotApplicable,
"OTH" => NullFlavor::Other,
other => NullFlavor::Unrecognized(other.to_string()),
}
}
#[must_use]
pub fn as_code(&self) -> &str {
match self {
NullFlavor::NoInformation => "NI",
NullFlavor::Unknown => "UNK",
NullFlavor::AskedButUnknown => "ASKU",
NullFlavor::NotAsked => "NASK",
NullFlavor::TemporarilyUnavailable => "NAV",
NullFlavor::NotApplicable => "NA",
NullFlavor::Other => "OTH",
NullFlavor::Unrecognized(code) => code,
}
}
#[must_use]
pub fn of(element: &hl7_2_xml_lite_helper::Element) -> Option<NullFlavor> {
element.attribute("nullFlavor").map(NullFlavor::parse)
}
}
impl Ii {
#[must_use]
pub(crate) fn from_element(element: &hl7_2_xml_lite_helper::Element) -> Option<Ii> {
let root = element.attribute("root")?.to_string();
let extension = element.attribute("extension").map(str::to_string);
Some(Ii { root, extension })
}
}
impl Ivl {
#[must_use]
pub fn from_element(element: &hl7_2_xml_lite_helper::Element) -> Ivl {
Ivl {
value: element.attribute("value").map(str::to_string),
low: element
.child("low")
.and_then(|low| low.attribute("value"))
.map(str::to_string),
high: element
.child("high")
.and_then(|high| high.attribute("value"))
.map(str::to_string),
}
}
}
impl Pq {
#[must_use]
pub fn from_element(element: &hl7_2_xml_lite_helper::Element) -> Pq {
Pq {
value: element.attribute("value").map(str::to_string),
unit: element.attribute("unit").map(str::to_string),
}
}
}
impl Ed {
#[must_use]
pub fn from_element(element: &hl7_2_xml_lite_helper::Element) -> Ed {
Ed {
media_type: element.attribute("mediaType").map(str::to_string),
representation: element.attribute("representation").map(str::to_string),
text: element.text_opt().map(str::to_string),
}
}
}
impl Cd {
#[must_use]
pub(crate) fn from_element(element: &hl7_2_xml_lite_helper::Element) -> Option<Cd> {
let code = element.attribute("code")?.to_string();
let code_system = element.attribute("codeSystem").map(str::to_string);
let display_name = element.attribute("displayName").map(str::to_string);
Some(Cd {
code,
code_system,
display_name,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ii_reads_root_and_extension() {
let element = hl7_2_xml_lite_helper::parse(
r#"<id root="2.16.840.1.113883.19.5" extension="12345"/>"#,
)
.unwrap();
let ii = Ii::from_element(&element).unwrap();
assert_eq!(ii.root, "2.16.840.1.113883.19.5");
assert_eq!(ii.extension.as_deref(), Some("12345"));
}
#[test]
fn ii_extension_is_optional() {
let element =
hl7_2_xml_lite_helper::parse(r#"<id root="2.16.840.1.113883.19.5"/>"#).unwrap();
let ii = Ii::from_element(&element).unwrap();
assert_eq!(ii.extension, None);
}
#[test]
fn ii_with_no_root_is_none() {
let element = hl7_2_xml_lite_helper::parse(r#"<id extension="12345"/>"#).unwrap();
assert_eq!(Ii::from_element(&element), None);
}
#[test]
fn cd_reads_code_system_and_display_name() {
let element = hl7_2_xml_lite_helper::parse(
r#"<code code="OBS" codeSystem="2.16.840.1.113883.5.6" displayName="Observation"/>"#,
)
.unwrap();
let cd = Cd::from_element(&element).unwrap();
assert_eq!(cd.code, "OBS");
assert_eq!(cd.code_system.as_deref(), Some("2.16.840.1.113883.5.6"));
assert_eq!(cd.display_name.as_deref(), Some("Observation"));
}
#[test]
fn cd_with_no_code_is_none() {
let element = hl7_2_xml_lite_helper::parse(r#"<code displayName="Observation"/>"#).unwrap();
assert_eq!(Cd::from_element(&element), None);
}
#[test]
fn ivl_reads_a_point_value() {
let element = hl7_2_xml_lite_helper::parse(r#"<effectiveTime value="20260101"/>"#).unwrap();
let ivl = Ivl::from_element(&element);
assert_eq!(ivl.value.as_deref(), Some("20260101"));
assert_eq!(ivl.low, None);
assert_eq!(ivl.high, None);
}
#[test]
fn ivl_reads_low_and_high() {
let element = hl7_2_xml_lite_helper::parse(
r#"<effectiveTime><low value="20260101"/><high value="20261231"/></effectiveTime>"#,
)
.unwrap();
let ivl = Ivl::from_element(&element);
assert_eq!(ivl.value, None);
assert_eq!(ivl.low.as_deref(), Some("20260101"));
assert_eq!(ivl.high.as_deref(), Some("20261231"));
}
#[test]
fn ivl_with_nothing_reads_all_none() {
let element = hl7_2_xml_lite_helper::parse(r"<effectiveTime/>").unwrap();
assert_eq!(Ivl::from_element(&element), Ivl::default());
}
#[test]
fn pq_reads_value_and_unit() {
let element =
hl7_2_xml_lite_helper::parse(r#"<doseQuantity value="5" unit="mg"/>"#).unwrap();
let pq = Pq::from_element(&element);
assert_eq!(pq.value.as_deref(), Some("5"));
assert_eq!(pq.unit.as_deref(), Some("mg"));
}
#[test]
fn ed_reads_media_type_representation_and_text() {
let element = hl7_2_xml_lite_helper::parse(
r#"<text mediaType="text/plain" representation="TXT">Patient reports pain.</text>"#,
)
.unwrap();
let ed = Ed::from_element(&element);
assert_eq!(ed.media_type.as_deref(), Some("text/plain"));
assert_eq!(ed.representation.as_deref(), Some("TXT"));
assert_eq!(ed.text.as_deref(), Some("Patient reports pain."));
}
#[test]
fn ed_with_no_attributes_still_reads_text() {
let element = hl7_2_xml_lite_helper::parse(r"<text>Plain narrative.</text>").unwrap();
let ed = Ed::from_element(&element);
assert_eq!(ed.media_type, None);
assert_eq!(ed.representation, None);
assert_eq!(ed.text.as_deref(), Some("Plain narrative."));
}
#[test]
fn null_flavor_parses_the_seven_named_codes() {
assert_eq!(NullFlavor::parse("NI"), NullFlavor::NoInformation);
assert_eq!(NullFlavor::parse("UNK"), NullFlavor::Unknown);
assert_eq!(NullFlavor::parse("ASKU"), NullFlavor::AskedButUnknown);
assert_eq!(NullFlavor::parse("NASK"), NullFlavor::NotAsked);
assert_eq!(NullFlavor::parse("NAV"), NullFlavor::TemporarilyUnavailable);
assert_eq!(NullFlavor::parse("NA"), NullFlavor::NotApplicable);
assert_eq!(NullFlavor::parse("OTH"), NullFlavor::Other);
}
#[test]
fn null_flavor_parse_and_as_code_round_trip() {
for code in ["NI", "UNK", "ASKU", "NASK", "NAV", "NA", "OTH", "MSK"] {
assert_eq!(NullFlavor::parse(code).as_code(), code);
}
}
#[test]
fn null_flavor_of_reads_the_attribute() {
let element = hl7_2_xml_lite_helper::parse(r#"<value nullFlavor="UNK"/>"#).unwrap();
assert_eq!(NullFlavor::of(&element), Some(NullFlavor::Unknown));
let element = hl7_2_xml_lite_helper::parse(r#"<value value="7"/>"#).unwrap();
assert_eq!(NullFlavor::of(&element), None);
}
}