hl7_parser/message/
separators.rs1use std::fmt::Display;
2
3#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct Separators {
7 pub field: char,
8 pub component: char,
9 pub subcomponent: char,
10 pub repetition: char,
11 pub escape: char,
12 pub lenient_newlines: bool,
16}
17
18impl Default for Separators {
19 fn default() -> Self {
33 Separators {
34 field: '|',
35 component: '^',
36 subcomponent: '&',
37 repetition: '~',
38 escape: '\\',
39 lenient_newlines: false,
40 }
41 }
42}
43
44impl Separators {
45 pub fn encode<'m>(&'m self, value: &'m str) -> EncodedSeparatorsDisplay<'m> {
59 EncodedSeparatorsDisplay {
60 separators: self,
61 value,
62 }
63 }
64
65 pub fn decode<'m>(&'m self, value: &'m str) -> DecodedSeparatorsDisplay<'m> {
78 DecodedSeparatorsDisplay {
79 separators: self,
80 value,
81 }
82 }
83
84 pub fn with_lenient_newlines(&mut self, lenient_newlines: bool) -> Self {
87 self.lenient_newlines = lenient_newlines;
88 *self
89 }
90}
91
92impl Display for Separators {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 write!(
95 f,
96 "{}{}{}{}{}",
97 self.field, self.component, self.repetition, self.escape, self.subcomponent
98 )
99 }
100}
101
102pub struct EncodedSeparatorsDisplay<'m> {
105 pub(crate) separators: &'m Separators,
106 pub(crate) value: &'m str,
107}
108
109impl Display for EncodedSeparatorsDisplay<'_> {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 for c in self.value.chars() {
112 if c == '\r' {
113 write!(f, "{escape}X0D{escape}", escape = self.separators.escape)?;
114 } else if c == '\n' {
115 write!(f, "{escape}X0A{escape}", escape = self.separators.escape)?;
116 } else if c == self.separators.field {
117 write!(f, "{escape}F{escape}", escape = self.separators.escape)?;
118 } else if c == self.separators.repetition {
119 write!(f, "{escape}R{escape}", escape = self.separators.escape)?;
120 } else if c == self.separators.component {
121 write!(f, "{escape}S{escape}", escape = self.separators.escape)?;
122 } else if c == self.separators.subcomponent {
123 write!(f, "{escape}T{escape}", escape = self.separators.escape)?;
124 } else if c == self.separators.escape {
125 write!(f, "{escape}E{escape}", escape = self.separators.escape)?;
126 } else {
127 write!(f, "{}", c)?;
128 }
129 }
130 Ok(())
131 }
132}
133
134pub struct DecodedSeparatorsDisplay<'m> {
136 pub(crate) separators: &'m Separators,
137 pub(crate) value: &'m str,
138}
139
140impl Display for DecodedSeparatorsDisplay<'_> {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 let mut escaped = false;
143 let mut escape_i: usize = 0;
144 for (i, c) in self.value.chars().enumerate() {
145 if c == self.separators.escape {
146 if escaped {
147 escaped = false;
148 match &self.value[escape_i..i] {
149 "F" => write!(f, "{}", self.separators.field)?,
150 "R" => write!(f, "{}", self.separators.repetition)?,
151 "S" => write!(f, "{}", self.separators.component)?,
152 "T" => write!(f, "{}", self.separators.subcomponent)?,
153 "E" => write!(f, "{}", self.separators.escape)?,
154 "X0A" => writeln!(f)?,
155 "X0D" | ".br" => write!(f, "\r")?,
156 v => write!(f, "{v}")?,
157 }
158 } else {
159 escape_i = i + 1;
160 escaped = true;
161 }
162 } else if !escaped {
163 write!(f, "{}", c)?;
164 }
165 }
166 Ok(())
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173 use pretty_assertions_sorted::assert_eq;
174
175 #[test]
176 fn separators_can_encode() {
177 let separators = Separators::default();
178
179 let input = "foo|bar^baz&quux~quuz\\corge\rquack\nduck";
180 let expected = r"foo\F\bar\S\baz\T\quux\R\quuz\E\corge\X0D\quack\X0A\duck";
181 let actual = separators.encode(input).to_string();
182 assert_eq!(expected, actual);
183 }
184
185 #[test]
186 fn sample_encode() {
187 let separators = Separators::default();
188
189 let input = "Pierre DuRho^ne & Cie";
190 let expected = r"Pierre DuRho\S\ne \T\ Cie";
191 let actual = separators.encode(input).to_string();
192 assert_eq!(expected, actual);
193 }
194
195 #[test]
196 fn separators_can_decode() {
197 let separators = Separators::default();
198
199 let input = r"foo\F\bar\S\baz\T\quux\R\quuz\E\corge\X0D\quack\X0A\duck\.br\";
200 let expected = "foo|bar^baz&quux~quuz\\corge\rquack\nduck\r";
201 let actual = separators.decode(input).to_string();
202 assert_eq!(expected, actual);
203 }
204}