hl7_parser/builder/
mod.rs1mod segment;
38use std::fmt::Display;
39
40use display::MessageBuilderDisplay;
41pub use segment::*;
42
43mod field;
44pub use field::*;
45
46mod repeat;
47pub use repeat::*;
48
49mod component;
50pub use component::*;
51
52use crate::{message::Separators, Message};
53
54pub mod prelude {
56 pub use super::*;
57 pub use crate::message::Separators;
58}
59
60#[derive(Debug, Clone, PartialEq, Eq)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63#[derive(Default)]
64pub struct MessageBuilder {
65 separators: Separators,
66 segments: Vec<SegmentBuilder>,
67}
68
69impl MessageBuilder {
70 pub fn new(separators: Separators) -> Self {
72 MessageBuilder {
73 separators,
74 segments: Vec::new(),
75 }
76 }
77
78 pub fn push_segment(&mut self, segment: SegmentBuilder) {
80 self.segments.push(segment);
81 }
82
83 pub fn separators(&self) -> &Separators {
85 &self.separators
86 }
87
88 pub fn segments(&self) -> &[SegmentBuilder] {
90 &self.segments
91 }
92
93 pub fn segments_mut(&mut self) -> &mut Vec<SegmentBuilder> {
95 &mut self.segments
96 }
97
98 pub fn segment(&self, index: usize) -> Option<&SegmentBuilder> {
100 self.segments.get(index)
101 }
102
103 pub fn segment_mut(&mut self, index: usize) -> Option<&mut SegmentBuilder> {
105 self.segments.get_mut(index)
106 }
107
108 pub fn remove_segment(&mut self, index: usize) -> Option<SegmentBuilder> {
110 if index >= self.segments.len() {
111 return None;
112 }
113 Some(self.segments.remove(index))
114 }
115
116 pub fn segment_named<S: AsRef<str>>(&self, name: S) -> Option<&SegmentBuilder> {
118 self.segments
119 .iter()
120 .find(|segment| segment.name() == name.as_ref())
121 }
122
123 pub fn segment_named_mut<S: AsRef<str>>(&mut self, name: S) -> Option<&mut SegmentBuilder> {
125 self.segments
126 .iter_mut()
127 .find(|segment| segment.name() == name.as_ref())
128 }
129
130 pub fn remove_segment_named<S: AsRef<str>>(&mut self, name: S) -> Option<SegmentBuilder> {
132 let index = self
133 .segments
134 .iter()
135 .position(|segment| segment.name() == name.as_ref())?;
136 Some(self.segments.remove(index))
137 }
138
139 pub fn segment_n<S: AsRef<str>>(&self, name: S, n: usize) -> Option<&SegmentBuilder> {
141 debug_assert!(n > 0, "Segment numbers are 1-based");
142 let name = name.as_ref();
143 self.segments
144 .iter()
145 .filter(|s| s.name.as_str() == name)
146 .nth(n - 1)
147 }
148
149 pub fn segment_n_mut<S: AsRef<str>>(
151 &mut self,
152 name: S,
153 n: usize,
154 ) -> Option<&mut SegmentBuilder> {
155 debug_assert!(n > 0, "Segment numbers are 1-based");
156 let name = name.as_ref();
157 self.segments
158 .iter_mut()
159 .filter(|s| s.name.as_str() == name)
160 .nth(n - 1)
161 }
162
163 pub fn remove_segment_n<S: AsRef<str>>(&mut self, name: S, n: usize) -> Option<SegmentBuilder> {
165 debug_assert!(n > 0, "Segment numbers are 1-based");
166 let name = name.as_ref();
167 let index = self
168 .segments
169 .iter()
170 .enumerate()
171 .find(|(_, s)| s.name.as_str() == name)
172 .map(|(i, _)| i)?;
173 Some(self.segments.remove(index))
174 }
175
176 pub fn is_empty(&self) -> bool {
178 self.segments.is_empty()
179 }
180
181 pub fn clear(&mut self) {
183 self.segments.clear();
184 }
185
186 pub fn set_separators(&mut self, separators: Separators) {
188 self.separators = separators;
189 }
190
191 pub fn with_segment(mut self, segment: SegmentBuilder) -> Self {
193 self.push_segment(segment);
194 self
195 }
196
197 pub fn render_with_newlines(&self) -> MessageBuilderDisplay<'_> {
201 MessageBuilderDisplay {
202 message: self,
203 #[cfg(windows)]
204 line_endings: "\r\n",
205 #[cfg(not(windows))]
206 line_endings: "\n",
207 }
208 }
209
210 pub fn render_with_segment_separators<'a>(
212 &'a self,
213 line_endings: &'a str,
214 ) -> MessageBuilderDisplay<'a> {
215 MessageBuilderDisplay {
216 message: self,
217 line_endings,
218 }
219 }
220}
221
222impl Display for MessageBuilder {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 let mut first = true;
226 for segment in &self.segments {
227 if first {
228 first = false;
229 } else {
230 write!(f, "\r")?;
231 }
232 write!(f, "{}", segment.display(&self.separators))?;
233 }
234 Ok(())
235 }
236}
237
238mod display {
239 use super::*;
240
241 pub struct MessageBuilderDisplay<'a> {
243 pub(super) message: &'a MessageBuilder,
244 pub(super) line_endings: &'a str,
245 }
246
247 impl<'a> Display for MessageBuilderDisplay<'a> {
248 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249 let mut first = true;
250 for segment in &self.message.segments {
251 if first {
252 first = false;
253 } else {
254 write!(f, "{}", self.line_endings)?;
255 }
256 write!(f, "{}", segment.display(&self.message.separators))?;
257 }
258 Ok(())
259 }
260 }
261}
262
263impl<'m> From<&'m Message<'m>> for MessageBuilder {
265 fn from(message: &'m Message) -> Self {
266 let mut builder = MessageBuilder::new(message.separators);
267 builder.segments = message.segments().map(SegmentBuilder::from).collect();
268 builder
269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275 use pretty_assertions_sorted::assert_eq;
276
277 #[test]
278 fn can_roundtrip_messages() {
279 let message_src = include_str!("../../test_assets/sample_adt_a01.hl7");
280 let message = crate::parser::parse_message_with_lenient_newlines(message_src, true)
281 .expect("Can parse message");
282
283 let builder: MessageBuilder = MessageBuilder::from(&message);
284 let display = builder.render_with_newlines().to_string();
285 assert_eq!(message_src.trim(), display);
286 }
287}