1use crate::EdifactError;
8use crate::event::{EdifactEvent, EventEmitter, WriterEmitter};
9use std::io::Write;
10
11pub trait EdifactSerialize {
18 fn edifact_serialize<E: EventEmitter>(&self, emitter: &mut E) -> Result<(), EdifactError>;
20}
21
22pub trait EdifactCompositeSerialize {
27 fn edifact_serialize_composite<E: EventEmitter>(
29 &self,
30 emitter: &mut E,
31 ) -> Result<(), EdifactError>;
32}
33
34impl EdifactCompositeSerialize for Vec<String> {
35 fn edifact_serialize_composite<E: EventEmitter>(
36 &self,
37 emitter: &mut E,
38 ) -> Result<(), EdifactError> {
39 if self.is_empty() {
40 return emitter.emit(EdifactEvent::Element { value: "" });
41 }
42
43 emitter.emit(EdifactEvent::Element { value: &self[0] })?;
44 for component in self.iter().skip(1) {
45 emitter.emit(EdifactEvent::ComponentElement { value: component })?;
46 }
47 Ok(())
48 }
49}
50
51impl EdifactSerialize for str {
54 #[inline]
55 fn edifact_serialize<E: EventEmitter>(&self, emitter: &mut E) -> Result<(), EdifactError> {
56 emitter.emit(EdifactEvent::Element { value: self })
57 }
58}
59
60impl EdifactSerialize for String {
61 #[inline]
62 fn edifact_serialize<E: EventEmitter>(&self, emitter: &mut E) -> Result<(), EdifactError> {
63 emitter.emit(EdifactEvent::Element {
64 value: self.as_str(),
65 })
66 }
67}
68
69impl<T: EdifactSerialize> EdifactSerialize for Option<T> {
71 fn edifact_serialize<E: EventEmitter>(&self, emitter: &mut E) -> Result<(), EdifactError> {
72 match self {
73 Some(v) => v.edifact_serialize(emitter),
74 None => emitter.emit(EdifactEvent::Element { value: "" }),
75 }
76 }
77}
78
79impl<T: EdifactSerialize> EdifactSerialize for Vec<T> {
81 fn edifact_serialize<E: EventEmitter>(&self, emitter: &mut E) -> Result<(), EdifactError> {
82 for item in self {
83 item.edifact_serialize(emitter)?;
84 }
85 Ok(())
86 }
87}
88
89impl<T: EdifactSerialize> EdifactSerialize for [T] {
91 fn edifact_serialize<E: EventEmitter>(&self, emitter: &mut E) -> Result<(), EdifactError> {
92 for item in self {
93 item.edifact_serialize(emitter)?;
94 }
95 Ok(())
96 }
97}
98
99macro_rules! impl_serialize_via_display {
100 ($($t:ty),+ $(,)?) => {
101 $(
102 impl EdifactSerialize for $t {
103 fn edifact_serialize<E: EventEmitter>(&self, emitter: &mut E) -> Result<(), EdifactError> {
104 let mut buf = [0u8; 40];
107 let s = {
108 use std::io::Write as _;
109 let mut cursor = std::io::Cursor::new(&mut buf[..]);
110 write!(cursor, "{}", self).expect("numeric format into fixed buffer");
111 let len = cursor.position() as usize;
112 std::str::from_utf8(&buf[..len]).expect("numeric output is valid UTF-8")
113 };
114 emitter.emit(EdifactEvent::Element { value: s })
115 }
116 }
117 )+
118 };
119}
120
121impl_serialize_via_display!(
122 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool
123);
124
125pub fn to_writer<T, W>(inner: W, value: &T) -> Result<(), EdifactError>
129where
130 T: EdifactSerialize,
131 W: Write,
132{
133 let mut emitter = WriterEmitter::new(inner);
134 value.edifact_serialize(&mut emitter)?;
135 emitter.finish().map(|_| ())
136}
137
138pub fn to_bytes<T: EdifactSerialize>(value: &T) -> Result<Vec<u8>, EdifactError> {
140 let mut buf = Vec::new();
141 to_writer(&mut buf, value)?;
142 Ok(buf)
143}
144
145pub fn to_edifact_string<T: EdifactSerialize>(value: &T) -> Result<String, EdifactError> {
154 let bytes = to_bytes(value)?;
155 String::from_utf8(bytes).map_err(|_| EdifactError::InvalidUtf8)
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use crate::event::{OwnedEdifactEvent, VecEmitter};
162
163 struct BgmSegment {
164 doc_name_code: String,
165 pruef_id: String,
166 msg_function: Option<String>,
167 }
168
169 impl EdifactSerialize for BgmSegment {
170 fn edifact_serialize<E: EventEmitter>(&self, emitter: &mut E) -> Result<(), EdifactError> {
171 emitter.emit(EdifactEvent::StartSegment { tag: "BGM" })?;
172 emitter.emit(EdifactEvent::Element {
173 value: &self.doc_name_code,
174 })?;
175 emitter.emit(EdifactEvent::Element {
176 value: &self.pruef_id,
177 })?;
178 self.msg_function.edifact_serialize(emitter)?;
179 emitter.emit(EdifactEvent::EndSegment)?;
180 Ok(())
181 }
182 }
183
184 #[test]
185 fn vec_emitter_captures_segment_events() {
186 let seg = BgmSegment {
187 doc_name_code: "E03".to_owned(),
188 pruef_id: "11042".to_owned(),
189 msg_function: None,
190 };
191 let mut emitter = VecEmitter::default();
192 seg.edifact_serialize(&mut emitter).unwrap();
193
194 assert_eq!(
195 emitter.events[0],
196 OwnedEdifactEvent::StartSegment {
197 tag: "BGM".to_owned()
198 }
199 );
200 assert_eq!(emitter.events.last(), Some(&OwnedEdifactEvent::EndSegment));
201 }
202
203 #[test]
204 fn to_bytes_produces_valid_edifact() {
205 let seg = BgmSegment {
206 doc_name_code: "E03".to_owned(),
207 pruef_id: "11042".to_owned(),
208 msg_function: Some("9".to_owned()),
209 };
210 let bytes = to_bytes(&seg).unwrap();
211 assert_eq!(std::str::from_utf8(&bytes).unwrap(), "BGM+E03+11042+9'");
212 }
213
214 #[test]
215 fn option_none_emits_empty_element() {
216 let val: Option<String> = None;
217 let mut emitter = VecEmitter::default();
218 val.edifact_serialize(&mut emitter).unwrap();
219 assert_eq!(
220 emitter.events[0],
221 OwnedEdifactEvent::Element {
222 value: String::new()
223 }
224 );
225 }
226
227 #[test]
228 fn option_some_emits_value() {
229 let val: Option<String> = Some("TEST".to_owned());
230 let mut emitter = VecEmitter::default();
231 val.edifact_serialize(&mut emitter).unwrap();
232 assert_eq!(
233 emitter.events[0],
234 OwnedEdifactEvent::Element {
235 value: "TEST".to_owned()
236 }
237 );
238 }
239
240 #[test]
241 fn numeric_types_serialize_via_display() {
242 let mut emitter = VecEmitter::default();
243 42u32.edifact_serialize(&mut emitter).unwrap();
244 assert_eq!(
245 emitter.events[0],
246 OwnedEdifactEvent::Element {
247 value: "42".to_owned()
248 }
249 );
250 }
251
252 #[test]
253 fn vec_serializes_each_item() {
254 let segments = vec![
255 BgmSegment {
256 doc_name_code: "E03".to_owned(),
257 pruef_id: "11042".to_owned(),
258 msg_function: None,
259 },
260 BgmSegment {
261 doc_name_code: "E01".to_owned(),
262 pruef_id: "11043".to_owned(),
263 msg_function: None,
264 },
265 ];
266 let bytes = to_bytes(&segments).unwrap();
267 let s = std::str::from_utf8(&bytes).unwrap();
268 assert!(s.contains("BGM+E03+11042"));
269 assert!(s.contains("BGM+E01+11043"));
270 }
271}