edifact_parser/
segment_builder.rs1use edifact_primitives::{EdifactDelimiters, RawSegment, SegmentPosition};
2
3use crate::EdifactTokenizer;
4
5pub struct SegmentBuilder {
10 tokenizer: EdifactTokenizer,
11}
12
13impl SegmentBuilder {
14 pub fn new(delimiters: EdifactDelimiters) -> Self {
16 Self {
17 tokenizer: EdifactTokenizer::new(delimiters),
18 }
19 }
20
21 pub fn build<'a>(
28 &self,
29 segment_str: &'a str,
30 position: SegmentPosition,
31 ) -> Option<RawSegment<'a>> {
32 if segment_str.is_empty() {
33 return None;
34 }
35
36 let mut elements_iter = self.tokenizer.tokenize_elements(segment_str);
37
38 let id = elements_iter.next()?;
40 if id.is_empty() {
41 return None;
42 }
43
44 let mut elements = Vec::new();
46 for element_str in elements_iter {
47 let components: Vec<&'a str> =
48 self.tokenizer.tokenize_components(element_str).collect();
49 elements.push(components);
50 }
51
52 Some(RawSegment::new(id, elements, position))
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 fn pos(n: u32, offset: usize) -> SegmentPosition {
61 SegmentPosition::new(n, offset, 1)
62 }
63
64 #[test]
65 fn test_build_simple_segment() {
66 let builder = SegmentBuilder::new(EdifactDelimiters::default());
67 let seg = builder
68 .build("UNH+00001+UTILMD:D:11A:UN:S2.1", pos(1, 0))
69 .unwrap();
70
71 assert_eq!(seg.id, "UNH");
72 assert_eq!(seg.element_count(), 2);
73 assert_eq!(seg.get_element(0), "00001");
74 assert_eq!(seg.get_component(1, 0), "UTILMD");
75 assert_eq!(seg.get_component(1, 1), "D");
76 assert_eq!(seg.get_component(1, 2), "11A");
77 assert_eq!(seg.get_component(1, 3), "UN");
78 assert_eq!(seg.get_component(1, 4), "S2.1");
79 }
80
81 #[test]
82 fn test_build_nad_segment() {
83 let builder = SegmentBuilder::new(EdifactDelimiters::default());
84 let seg = builder
85 .build("NAD+Z04+9900123000002::293", pos(5, 100))
86 .unwrap();
87
88 assert_eq!(seg.id, "NAD");
89 assert_eq!(seg.get_element(0), "Z04");
90 assert_eq!(seg.get_component(1, 0), "9900123000002");
91 assert_eq!(seg.get_component(1, 1), "");
92 assert_eq!(seg.get_component(1, 2), "293");
93 }
94
95 #[test]
96 fn test_build_dtm_with_escaped_plus() {
97 let builder = SegmentBuilder::new(EdifactDelimiters::default());
98 let seg = builder
99 .build("DTM+137:202501010000?+01:303", pos(3, 50))
100 .unwrap();
101
102 assert_eq!(seg.id, "DTM");
103 assert_eq!(seg.get_component(0, 0), "137");
104 assert_eq!(seg.get_component(0, 1), "202501010000?+01");
105 assert_eq!(seg.get_component(0, 2), "303");
106 }
107
108 #[test]
109 fn test_build_segment_no_elements() {
110 let builder = SegmentBuilder::new(EdifactDelimiters::default());
111 let seg = builder.build("UNA", pos(1, 0)).unwrap();
112
113 assert_eq!(seg.id, "UNA");
114 assert_eq!(seg.element_count(), 0);
115 }
116
117 #[test]
118 fn test_build_empty_input() {
119 let builder = SegmentBuilder::new(EdifactDelimiters::default());
120 assert!(builder.build("", pos(1, 0)).is_none());
121 }
122
123 #[test]
124 fn test_build_loc_segment() {
125 let builder = SegmentBuilder::new(EdifactDelimiters::default());
126 let seg = builder
127 .build("LOC+Z16+DE00014545768S0000000000000003054", pos(8, 200))
128 .unwrap();
129
130 assert_eq!(seg.id, "LOC");
131 assert_eq!(seg.get_element(0), "Z16");
132 assert_eq!(seg.get_element(1), "DE00014545768S0000000000000003054");
133 }
134
135 #[test]
136 fn test_build_preserves_position() {
137 let builder = SegmentBuilder::new(EdifactDelimiters::default());
138 let seg = builder.build("BGM+E03+DOC001", pos(2, 42)).unwrap();
139
140 assert_eq!(seg.position.segment_number, 2);
141 assert_eq!(seg.position.byte_offset, 42);
142 assert_eq!(seg.position.message_number, 1);
143 }
144
145 #[test]
146 fn test_build_rff_segment() {
147 let builder = SegmentBuilder::new(EdifactDelimiters::default());
148 let seg = builder.build("RFF+Z13:TXREF001", pos(10, 300)).unwrap();
149
150 assert_eq!(seg.id, "RFF");
151 assert_eq!(seg.get_component(0, 0), "Z13");
152 assert_eq!(seg.get_component(0, 1), "TXREF001");
153 }
154}