hl7_3/lib.rs
1//! Health Level Seven (HL7) version 3 (V3) for Rust — a foundation, not a
2//! complete implementation.
3//!
4//! HL7 v3 replaced v2's pipe-delimited text and per-message-type segment
5//! tables with one thing reused everywhere: the [Reference Information
6//! Model](rim) (RIM), six backbone classes ([`rim::Act`], [`rim::Entity`],
7//! [`rim::Role`], [`rim::Participation`], [`rim::ActRelationship`],
8//! [`rim::RoleLink`]) that every domain payload — lab results, care
9//! records, structured product labeling — is assembled from, serialized as
10//! XML instead of ER7. It achieved little messaging adoption of its own
11//! (implementers found the model-driven rigor expensive to work with) but
12//! its RIM and three-level structure live on directly inside the Clinical
13//! Document Architecture (CDA), which did succeed.
14//!
15//! ```
16//! use hl7_3::message;
17//!
18//! let xml = r#"
19//! <QUQI_IN000001UV01 xmlns="urn:hl7-org:v3">
20//! <id root="2.16.840.1.113883.19.5" extension="MSG00001"/>
21//! <interactionId root="2.16.840.1.113883.1.6" extension="QUQI_IN000001UV01"/>
22//! <controlActProcess classCode="CACT" moodCode="EVN">
23//! <code code="QUQI_TE000001UV01"/>
24//! <subject>
25//! <observation classCode="OBS" moodCode="EVN"/>
26//! </subject>
27//! </controlActProcess>
28//! </QUQI_IN000001UV01>
29//! "#;
30//! let parsed = message::parse(xml)?;
31//! assert_eq!(parsed.control_act.unwrap().domain.unwrap().local_name(), "observation");
32//! # Ok::<(), hl7_3::Error>(())
33//! ```
34//!
35//! ## What this crate is, and is not
36//!
37//! It is: the RIM backbone classes as Rust types ([`rim`]), the data types
38//! RIM attributes are built from — identifiers, coded values, intervals,
39//! quantities, encapsulated data, and the explicit-null mechanism any of
40//! them can carry instead of a value ([`vocabulary`]) — and a reader for
41//! the three-level message envelope every interaction shares ([`message`])
42//! — transport wrapper, control act wrapper, domain payload.
43//!
44//! It is not: a validator against any of HL7 v3's vocabulary domains or
45//! interaction schemas, a CDA document model, or a decoder for any
46//! specific domain payload's internal shape (a lab result, a care record)
47//! — those vary per interaction and are read with [`rim`] types by the
48//! caller, the same way generic mode in
49//! [`hl7-2`](https://crates.io/crates/hl7-2) hands back a tree rather than
50//! a typed message. `spec/index.md` is the exact, current statement of
51//! scope; where this comment and that document disagree, the document is
52//! right.
53//!
54//! For a stable, long-lived interaction, [`typed::FromElement`] — derived
55//! with `#[derive(FromElement)]` behind the `derive` feature
56//! ([`hl7-3-derive`](https://crates.io/crates/hl7-3-derive)) — maps a
57//! struct's fields onto an element's attributes and children once, the way
58//! `hl7-2`'s struct mode does for v2 paths. See [`typed`] for the
59//! attributes and an example.
60
61#![warn(missing_docs, clippy::pedantic)]
62
63pub mod message;
64pub mod rim;
65pub mod typed;
66pub mod vocabulary;
67
68pub use message::{ControlAct, Message};
69pub use typed::{FromElement, FromElementValue};
70pub use vocabulary::{Cd, Ed, Ii, Ivl, NullFlavor, Pq};
71
72/// The `#[derive(FromElement)]` macro, re-exported so the `hl7-3-derive`
73/// crate does not have to be named as a dependency. Requires the `derive`
74/// feature. (Same name as the [`typed::FromElement`] trait, deliberately —
75/// like `hl7-2`'s `FromHl7`, Rust keeps a derive macro and a trait of the
76/// same name in separate namespaces, so `#[derive(FromElement)]` and `impl
77/// FromElement` never conflict.)
78#[cfg(feature = "derive")]
79pub use hl7_3_derive::FromElement;
80
81/// The XML reader this crate reads HL7 v3 messages through, re-exported so
82/// callers can name [`xml::Element`] without adding their own dependency.
83pub use hl7_2_xml_lite_helper as xml;
84
85/// What can go wrong.
86#[derive(Debug, Clone, PartialEq, Eq)]
87pub enum Error {
88 /// The input is not well-formed XML.
89 Xml(hl7_2_xml_lite_helper::Error),
90}
91
92impl std::fmt::Display for Error {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 match self {
95 Error::Xml(error) => write!(f, "not well-formed XML: {error}"),
96 }
97 }
98}
99
100impl std::error::Error for Error {}
101
102impl From<hl7_2_xml_lite_helper::Error> for Error {
103 fn from(error: hl7_2_xml_lite_helper::Error) -> Error {
104 Error::Xml(error)
105 }
106}