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
84#[derive(Debug, Default)]
90pub struct VecEmitter {
91 pub events: Vec<OwnedEdifactEvent>,
93}
94
95impl EventEmitter for VecEmitter {
96 fn emit(&mut self, event: EdifactEvent<'_>) -> Result<(), EdifactError> {
97 self.events.push(event.into_owned());
98 Ok(())
99 }
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106enum EmitterState {
107 Idle,
109 InSegment,
111 InElement,
113}
114
115pub struct WriterEmitter<W: Write> {
131 writer: crate::Writer<W>,
132 state: EmitterState,
133}
134
135impl<W: Write> WriterEmitter<W> {
136 pub fn new(inner: W) -> Self {
138 Self {
139 writer: crate::Writer::new(inner),
140 state: EmitterState::Idle,
141 }
142 }
143
144 pub fn finish(self) -> Result<W, EdifactError> {
146 self.writer.finish()
147 }
148
149 pub fn segment_count(&self) -> u64 {
151 self.writer.segment_count()
152 }
153}
154
155impl<W: Write> EventEmitter for WriterEmitter<W> {
156 fn emit(&mut self, event: EdifactEvent<'_>) -> Result<(), EdifactError> {
157 match event {
158 EdifactEvent::StartSegment { tag } => {
159 if self.state != EmitterState::Idle {
160 return Err(EdifactError::InvalidEventSequence {
161 message: "StartSegment emitted while a segment is already open; emit EndSegment first",
162 });
163 }
164 self.state = EmitterState::InSegment;
165 self.writer.write_tag_only(tag)?;
166 }
167 EdifactEvent::Element { value } => {
168 if self.state == EmitterState::Idle {
169 return Err(EdifactError::InvalidEventSequence {
170 message: "Element emitted outside of a segment; emit StartSegment first",
171 });
172 }
173 self.state = EmitterState::InElement;
174 self.writer.write_element_sep()?;
175 self.writer.write_escaped(value)?;
176 }
177 EdifactEvent::ComponentElement { value } => {
178 if self.state != EmitterState::InElement {
179 return Err(EdifactError::InvalidEventSequence {
180 message: "ComponentElement emitted without a preceding Element in the same segment",
181 });
182 }
183 self.writer.write_component_sep()?;
184 self.writer.write_escaped(value)?;
185 }
186 EdifactEvent::EndSegment => {
187 if self.state == EmitterState::Idle {
188 return Err(EdifactError::InvalidEventSequence {
189 message: "EndSegment emitted while no segment is open; emit StartSegment first",
190 });
191 }
192 self.state = EmitterState::Idle;
193 self.writer.write_segment_term_and_count()?;
194 }
195 }
196 Ok(())
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn vec_emitter_no_memory_leak() {
206 let mut e = VecEmitter::default();
207 e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
208 e.emit(EdifactEvent::Element { value: "E03" }).unwrap();
209 e.emit(EdifactEvent::EndSegment).unwrap();
210 assert_eq!(
211 e.events[0],
212 OwnedEdifactEvent::StartSegment {
213 tag: "BGM".to_owned()
214 }
215 );
216 assert_eq!(
217 e.events[1],
218 OwnedEdifactEvent::Element {
219 value: "E03".to_owned()
220 }
221 );
222 }
223
224 #[test]
225 fn writer_emitter_produces_valid_edifact() {
226 let mut buf = Vec::new();
227 {
228 let mut e = WriterEmitter::new(&mut buf);
229 e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
230 e.emit(EdifactEvent::Element { value: "E03" }).unwrap();
231 e.emit(EdifactEvent::Element { value: "11042" }).unwrap();
232 e.emit(EdifactEvent::EndSegment).unwrap();
233 e.finish().unwrap();
234 }
235 assert_eq!(buf, b"BGM+E03+11042'");
236 }
237
238 #[test]
239 fn writer_emitter_handles_components() {
240 let mut buf = Vec::new();
241 {
242 let mut e = WriterEmitter::new(&mut buf);
243 e.emit(EdifactEvent::StartSegment { tag: "NAD" }).unwrap();
244 e.emit(EdifactEvent::Element { value: "MS" }).unwrap();
245 e.emit(EdifactEvent::Element {
246 value: "9900112233445",
247 })
248 .unwrap();
249 e.emit(EdifactEvent::ComponentElement { value: "" })
250 .unwrap();
251 e.emit(EdifactEvent::ComponentElement { value: "293" })
252 .unwrap();
253 e.emit(EdifactEvent::EndSegment).unwrap();
254 e.finish().unwrap();
255 }
256 let s = std::str::from_utf8(&buf).unwrap();
257 assert_eq!(s, "NAD+MS+9900112233445::293'");
258 }
259
260 #[test]
263 fn writer_emitter_element_before_start_segment_is_err() {
264 let mut e = WriterEmitter::new(Vec::<u8>::new());
265 let err = e
266 .emit(EdifactEvent::Element { value: "X" })
267 .unwrap_err();
268 assert!(
269 matches!(err, crate::EdifactError::InvalidEventSequence { .. }),
270 "expected InvalidEventSequence, got {err:?}"
271 );
272 }
273
274 #[test]
275 fn writer_emitter_component_before_element_is_err() {
276 let mut e = WriterEmitter::new(Vec::<u8>::new());
277 e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
278 let err = e
279 .emit(EdifactEvent::ComponentElement { value: "X" })
280 .unwrap_err();
281 assert!(
282 matches!(err, crate::EdifactError::InvalidEventSequence { .. }),
283 "expected InvalidEventSequence, got {err:?}"
284 );
285 }
286
287 #[test]
288 fn writer_emitter_double_start_segment_is_err() {
289 let mut e = WriterEmitter::new(Vec::<u8>::new());
290 e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
291 let err = e
292 .emit(EdifactEvent::StartSegment { tag: "DTM" })
293 .unwrap_err();
294 assert!(
295 matches!(err, crate::EdifactError::InvalidEventSequence { .. }),
296 "expected InvalidEventSequence, got {err:?}"
297 );
298 }
299
300 #[test]
301 fn writer_emitter_end_segment_without_start_is_err() {
302 let mut e = WriterEmitter::new(Vec::<u8>::new());
303 let err = e.emit(EdifactEvent::EndSegment).unwrap_err();
304 assert!(
305 matches!(err, crate::EdifactError::InvalidEventSequence { .. }),
306 "expected InvalidEventSequence, got {err:?}"
307 );
308 }
309}