1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! # serde-er7
//!
//! **[website](https://er7-rust.github.io/serde-er7/)**
//! •
//! **[documentation](https://docs.rs/serde-er7/)**
//! •
//! **[source](https://github.com/er7-rust/er7-rust/tree/main/serde-er7)**
//! •
//! **[crate](https://crates.io/crates/serde-er7)**
//! •
//! **[email](mailto:joel@joelparkerhenderson.com)**
//!
//! Serde support for [`er7`], the pipe-hat encoding that carries HL7 v2
//! messages between healthcare systems.
//!
//! [`er7`] parses, queries, edits, and writes ER7 text, deliberately with
//! no dependencies of its own. This crate is the bridge from that value
//! tree to the rest of the Serde ecosystem: wrap a parsed [`er7::Message`]
//! in [`Message`], and it can flow through `serde_json`, `serde_yaml`,
//! `bincode`, or any other Serde data format — for storing a parsed
//! message in a document database, logging it as structured JSON,
//! returning it from a web API, or testing it with `assert_eq!` against a
//! literal.
//!
//! Every impl in this crate is written by hand against the low-level
//! `Serializer`/`Deserializer`/`Visitor` traits, following the pattern
//! [serde's own documentation](https://docs.rs/serde/latest/serde/)
//! walks through for a manual implementation — no `#[derive(Serialize)]`
//! anywhere, because [`er7`]'s tree cannot derive its way to the shapes
//! below (a bare array for a field's repetitions, a bare string for a
//! leaf) without help.
//!
//! Example:
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use serde_er7::Message;
//!
//! let text = "MSH|^~\\&|LAB|ACME|EHR|CLINIC|20260815120000||ORU^R01|MSG9|P|2.5\r\
//! PID|1||12345^^^ACME^MR||SMITH^JOHN^Q||19800101|M\r\
//! OBX|1|NM|2093-3^Cholesterol^LN||187|mg/dL|||||F";
//!
//! let message = Message::parse(text)?;
//!
//! // Out to JSON, and back — this crate never mentions JSON itself; any
//! // Serde format works the same way.
//! let json = serde_json::to_string(&message)?;
//! let back: Message = serde_json::from_str(&json)?;
//!
//! assert_eq!(back.to_er7(), text);
//! # Ok(())
//! # }
//! ```
//!
//! # The shape each level serializes as
//!
//! | Level | Wrapper | Serializes as |
//! |-------|---------|----------------|
//! | Message | [`Message`] | object: `{"separators": ..., "segments": [...]}` |
//! | Segment | [`Segment`] | object: `{"name": "PID", "fields": [...]}` |
//! | Field | [`Field`] | array of repetitions |
//! | Repetition | [`Repetition`] | array of components |
//! | Component | [`Component`] | array of subcomponent strings |
//! | Subcomponent | [`Subcomponent`] | a bare string, `raw` (not [`er7::Subcomponent::value`]-decoded) |
//! | Separators | [`Separators`] | object of six named fields, chars as one-character strings |
//! | Terminator | [`Terminator`] | one of the strings `"Cr"`, `"Lf"`, `"CrLf"` |
//!
//! Every level below [`Message`] is optional to reach for directly — most
//! callers only ever construct a [`Message`] and let its `Serialize` impl
//! walk the rest of the tree. The lower levels are `pub` so a caller who
//! only wants to serialize one segment, or one field, out of a larger
//! message can do that too.
//!
//! # What is deliberately not here
//!
//! This crate adds exactly one thing to [`er7`]: Serde support for its
//! existing value tree. It does not add a dictionary, a validator, or a
//! transport — [`er7`] does not have those either, and a bridge crate is
//! the wrong place to add what the crate it bridges declined to have. See
//! [`er7`]'s own documentation for what "encoding, not dictionary" means in
//! practice.
//!
//! It also does not pick a wire format. `serde_json` appears only as a
//! dev-dependency, to test and demonstrate against — the whole point of
//! building against `serde`'s traits rather than writing an ER7-to-JSON
//! converter directly is that the format is the caller's choice, not this
//! crate's.
//!
//! # Documentation
//!
//! `spec/index.md` in the repository is this crate's specification —
//! what each wrapper type must serialize as and why, following the same
//! spec-driven process [`er7`] itself uses. A tutorial is in
//! `docs/usage/index.md`, and runnable programs are in `examples/`.
pub use Component;
pub use Field;
pub use Message;
pub use Repetition;
pub use Segment;
pub use Separators;
pub use Subcomponent;
pub use Terminator;
// Re-exported so a caller can name `er7::Message`, `er7::Error`, and the
// rest without adding their own dependency on `er7` — the same convenience
// `hl7-2-5-to-xml-using-rust` and `hl7-2-5-to-json-using-rust` extend for
// the crates they build on top of.
pub use er7;