1use crate::EdifactError;
8use std::io::Write;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
14#[non_exhaustive]
15pub enum EdifactEvent<'a> {
16 StartSegment {
18 tag: &'a str,
20 },
21 Element {
23 value: &'a str,
25 },
26 ComponentElement {
28 value: &'a str,
30 },
31 EndSegment,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
37#[non_exhaustive]
38pub enum OwnedEdifactEvent {
39 StartSegment {
41 tag: String,
43 },
44 Element {
46 value: String,
48 },
49 ComponentElement {
51 value: String,
53 },
54 EndSegment,
56}
57
58impl<'a> EdifactEvent<'a> {
59 pub fn into_owned(self) -> OwnedEdifactEvent {
61 match self {
62 Self::StartSegment { tag } => OwnedEdifactEvent::StartSegment {
63 tag: tag.to_owned(),
64 },
65 Self::Element { value } => OwnedEdifactEvent::Element {
66 value: value.to_owned(),
67 },
68 Self::ComponentElement { value } => OwnedEdifactEvent::ComponentElement {
69 value: value.to_owned(),
70 },
71 Self::EndSegment => OwnedEdifactEvent::EndSegment,
72 }
73 }
74}
75
76pub trait EventEmitter {
80 fn emit(&mut self, event: EdifactEvent<'_>) -> Result<(), EdifactError>;
82
83 #[inline]
93 fn decimal_mark(&self) -> u8 {
94 b'.'
95 }
96}
97
98#[derive(Debug, Default)]
104pub struct VecEmitter {
105 pub events: Vec<OwnedEdifactEvent>,
107}
108
109impl EventEmitter for VecEmitter {
110 fn emit(&mut self, event: EdifactEvent<'_>) -> Result<(), EdifactError> {
111 self.events.push(event.into_owned());
112 Ok(())
113 }
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120enum EmitterState {
121 Idle,
123 InSegment,
125 InElement,
127}
128
129pub struct WriterEmitter<W: Write> {
145 writer: crate::Writer<W>,
146 state: EmitterState,
147}
148
149impl<W: Write> WriterEmitter<W> {
150 pub fn new(inner: W) -> Self {
152 Self {
153 writer: crate::Writer::new(inner),
154 state: EmitterState::Idle,
155 }
156 }
157
158 pub fn with_una(
164 inner: W,
165 ssa: crate::tokenizer::ServiceStringAdvice,
166 ) -> Result<Self, crate::EdifactError> {
167 Ok(Self {
168 writer: crate::Writer::with_una(inner, ssa)?,
169 state: EmitterState::Idle,
170 })
171 }
172
173 pub fn finish(self) -> Result<W, EdifactError> {
175 self.writer.finish()
176 }
177
178 pub fn segment_count(&self) -> u64 {
180 self.writer.segment_count()
181 }
182
183 pub fn service_string_advice(&self) -> crate::tokenizer::ServiceStringAdvice {
188 self.writer.service_string_advice()
189 }
190}
191
192impl<W: Write> EventEmitter for WriterEmitter<W> {
193 #[inline]
194 fn decimal_mark(&self) -> u8 {
195 self.writer.service_string_advice().decimal_mark
196 }
197
198 fn emit(&mut self, event: EdifactEvent<'_>) -> Result<(), EdifactError> {
199 match event {
200 EdifactEvent::StartSegment { tag } => {
201 if self.state != EmitterState::Idle {
202 return Err(EdifactError::InvalidEventSequence {
203 message: "StartSegment emitted while a segment is already open; emit EndSegment first",
204 });
205 }
206 self.state = EmitterState::InSegment;
207 self.writer.write_tag_only(tag)?;
208 }
209 EdifactEvent::Element { value } => {
210 if self.state == EmitterState::Idle {
211 return Err(EdifactError::InvalidEventSequence {
212 message: "Element emitted outside of a segment; emit StartSegment first",
213 });
214 }
215 self.state = EmitterState::InElement;
216 self.writer.write_element_sep()?;
217 self.writer.write_escaped(value)?;
218 }
219 EdifactEvent::ComponentElement { value } => {
220 if self.state != EmitterState::InElement {
221 return Err(EdifactError::InvalidEventSequence {
222 message: "ComponentElement emitted without a preceding Element in the same segment",
223 });
224 }
225 self.writer.write_component_sep()?;
226 self.writer.write_escaped(value)?;
227 }
228 EdifactEvent::EndSegment => {
229 if self.state == EmitterState::Idle {
230 return Err(EdifactError::InvalidEventSequence {
231 message: "EndSegment emitted while no segment is open; emit StartSegment first",
232 });
233 }
234 self.state = EmitterState::Idle;
235 self.writer.write_segment_term_and_count()?;
236 }
237 }
238 Ok(())
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245
246 #[test]
247 fn vec_emitter_no_memory_leak() {
248 let mut e = VecEmitter::default();
249 e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
250 e.emit(EdifactEvent::Element { value: "E03" }).unwrap();
251 e.emit(EdifactEvent::EndSegment).unwrap();
252 assert_eq!(
253 e.events[0],
254 OwnedEdifactEvent::StartSegment {
255 tag: "BGM".to_owned()
256 }
257 );
258 assert_eq!(
259 e.events[1],
260 OwnedEdifactEvent::Element {
261 value: "E03".to_owned()
262 }
263 );
264 }
265
266 #[test]
267 fn writer_emitter_produces_valid_edifact() {
268 let mut buf = Vec::new();
269 {
270 let mut e = WriterEmitter::new(&mut buf);
271 e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
272 e.emit(EdifactEvent::Element { value: "E03" }).unwrap();
273 e.emit(EdifactEvent::Element { value: "11042" }).unwrap();
274 e.emit(EdifactEvent::EndSegment).unwrap();
275 e.finish().unwrap();
276 }
277 assert_eq!(buf, b"BGM+E03+11042'");
278 }
279
280 #[test]
281 fn writer_emitter_handles_components() {
282 let mut buf = Vec::new();
283 {
284 let mut e = WriterEmitter::new(&mut buf);
285 e.emit(EdifactEvent::StartSegment { tag: "NAD" }).unwrap();
286 e.emit(EdifactEvent::Element { value: "MS" }).unwrap();
287 e.emit(EdifactEvent::Element {
288 value: "9900112233445",
289 })
290 .unwrap();
291 e.emit(EdifactEvent::ComponentElement { value: "" })
292 .unwrap();
293 e.emit(EdifactEvent::ComponentElement { value: "293" })
294 .unwrap();
295 e.emit(EdifactEvent::EndSegment).unwrap();
296 e.finish().unwrap();
297 }
298 let s = std::str::from_utf8(&buf).unwrap();
299 assert_eq!(s, "NAD+MS+9900112233445::293'");
300 }
301
302 #[test]
305 fn writer_emitter_element_before_start_segment_is_err() {
306 let mut e = WriterEmitter::new(Vec::<u8>::new());
307 let err = e.emit(EdifactEvent::Element { value: "X" }).unwrap_err();
308 assert!(
309 matches!(err, crate::EdifactError::InvalidEventSequence { .. }),
310 "expected InvalidEventSequence, got {err:?}"
311 );
312 }
313
314 #[test]
315 fn writer_emitter_component_before_element_is_err() {
316 let mut e = WriterEmitter::new(Vec::<u8>::new());
317 e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
318 let err = e
319 .emit(EdifactEvent::ComponentElement { value: "X" })
320 .unwrap_err();
321 assert!(
322 matches!(err, crate::EdifactError::InvalidEventSequence { .. }),
323 "expected InvalidEventSequence, got {err:?}"
324 );
325 }
326
327 #[test]
328 fn writer_emitter_double_start_segment_is_err() {
329 let mut e = WriterEmitter::new(Vec::<u8>::new());
330 e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
331 let err = e
332 .emit(EdifactEvent::StartSegment { tag: "DTM" })
333 .unwrap_err();
334 assert!(
335 matches!(err, crate::EdifactError::InvalidEventSequence { .. }),
336 "expected InvalidEventSequence, got {err:?}"
337 );
338 }
339
340 #[test]
341 fn writer_emitter_end_segment_without_start_is_err() {
342 let mut e = WriterEmitter::new(Vec::<u8>::new());
343 let err = e.emit(EdifactEvent::EndSegment).unwrap_err();
344 assert!(
345 matches!(err, crate::EdifactError::InvalidEventSequence { .. }),
346 "expected InvalidEventSequence, got {err:?}"
347 );
348 }
349}