use crate::EdifactError;
use std::io::Write;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EdifactEvent<'a> {
StartSegment {
tag: &'a str,
},
Element {
value: &'a str,
},
ComponentElement {
value: &'a str,
},
EndSegment,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OwnedEdifactEvent {
StartSegment {
tag: String,
},
Element {
value: String,
},
ComponentElement {
value: String,
},
EndSegment,
}
impl<'a> EdifactEvent<'a> {
pub fn into_owned(self) -> OwnedEdifactEvent {
match self {
Self::StartSegment { tag } => OwnedEdifactEvent::StartSegment {
tag: tag.to_owned(),
},
Self::Element { value } => OwnedEdifactEvent::Element {
value: value.to_owned(),
},
Self::ComponentElement { value } => OwnedEdifactEvent::ComponentElement {
value: value.to_owned(),
},
Self::EndSegment => OwnedEdifactEvent::EndSegment,
}
}
}
pub trait EventEmitter {
fn emit(&mut self, event: EdifactEvent<'_>) -> Result<(), EdifactError>;
}
#[derive(Debug, Default)]
pub struct VecEmitter {
pub events: Vec<OwnedEdifactEvent>,
}
impl EventEmitter for VecEmitter {
fn emit(&mut self, event: EdifactEvent<'_>) -> Result<(), EdifactError> {
self.events.push(event.into_owned());
Ok(())
}
}
pub struct WriterEmitter<W: Write> {
writer: crate::Writer<W>,
}
impl<W: Write> WriterEmitter<W> {
pub fn new(inner: W) -> Self {
Self {
writer: crate::Writer::new(inner),
}
}
pub fn finish(self) -> Result<W, EdifactError> {
self.writer.finish()
}
pub fn segment_count(&self) -> u32 {
self.writer.segment_count()
}
}
impl<W: Write> EventEmitter for WriterEmitter<W> {
fn emit(&mut self, event: EdifactEvent<'_>) -> Result<(), EdifactError> {
match event {
EdifactEvent::StartSegment { tag } => {
self.writer.write_tag_only(tag)?;
}
EdifactEvent::Element { value } => {
self.writer.write_element_sep()?;
self.writer.write_escaped(value)?;
}
EdifactEvent::ComponentElement { value } => {
self.writer.write_component_sep()?;
self.writer.write_escaped(value)?;
}
EdifactEvent::EndSegment => {
self.writer.write_segment_term_and_count()?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vec_emitter_no_memory_leak() {
let mut e = VecEmitter::default();
e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
e.emit(EdifactEvent::Element { value: "E03" }).unwrap();
e.emit(EdifactEvent::EndSegment).unwrap();
assert_eq!(
e.events[0],
OwnedEdifactEvent::StartSegment {
tag: "BGM".to_owned()
}
);
assert_eq!(
e.events[1],
OwnedEdifactEvent::Element {
value: "E03".to_owned()
}
);
}
#[test]
fn writer_emitter_produces_valid_edifact() {
let mut buf = Vec::new();
{
let mut e = WriterEmitter::new(&mut buf);
e.emit(EdifactEvent::StartSegment { tag: "BGM" }).unwrap();
e.emit(EdifactEvent::Element { value: "E03" }).unwrap();
e.emit(EdifactEvent::Element { value: "11042" }).unwrap();
e.emit(EdifactEvent::EndSegment).unwrap();
e.finish().unwrap();
}
assert_eq!(buf, b"BGM+E03+11042'");
}
#[test]
fn writer_emitter_handles_components() {
let mut buf = Vec::new();
{
let mut e = WriterEmitter::new(&mut buf);
e.emit(EdifactEvent::StartSegment { tag: "NAD" }).unwrap();
e.emit(EdifactEvent::Element { value: "MS" }).unwrap();
e.emit(EdifactEvent::Element {
value: "9900112233445",
})
.unwrap();
e.emit(EdifactEvent::ComponentElement { value: "" })
.unwrap();
e.emit(EdifactEvent::ComponentElement { value: "293" })
.unwrap();
e.emit(EdifactEvent::EndSegment).unwrap();
e.finish().unwrap();
}
let s = std::str::from_utf8(&buf).unwrap();
assert_eq!(s, "NAD+MS+9900112233445::293'");
}
}