Skip to main content

edifact_parser/
handler.rs

1use edifact_primitives::{Control, EdifactDelimiters, RawSegment};
2
3use crate::ParseError;
4
5/// Trait for handling EDIFACT parsing events.
6///
7/// All methods have default no-op implementations, so implementors
8/// only need to override the callbacks they care about.
9///
10/// # Event Order
11///
12/// For a typical EDIFACT interchange:
13/// 1. `on_delimiters()` — always called first
14/// 2. `on_interchange_start()` — when UNB is encountered
15/// 3. `on_message_start()` — when UNH is encountered
16/// 4. `on_segment()` — for EVERY segment (including UNB, UNH, UNT, UNZ)
17/// 5. `on_message_end()` — when UNT is encountered
18/// 6. `on_interchange_end()` — when UNZ is encountered
19pub trait EdifactHandler {
20    /// Called when delimiters are determined (from UNA or defaults).
21    fn on_delimiters(&mut self, _delimiters: &EdifactDelimiters, _explicit_una: bool) {}
22
23    /// Called when an interchange begins (UNB segment).
24    fn on_interchange_start(&mut self, _unb: &RawSegment) -> Control {
25        Control::Continue
26    }
27
28    /// Called when a message begins (UNH segment).
29    fn on_message_start(&mut self, _unh: &RawSegment) -> Control {
30        Control::Continue
31    }
32
33    /// Called for every segment in the interchange.
34    ///
35    /// This is called for ALL segments, including service segments
36    /// (UNB, UNH, UNT, UNZ). The specific `on_*` methods are called
37    /// BEFORE `on_segment()` for service segments.
38    fn on_segment(&mut self, _segment: &RawSegment) -> Control {
39        Control::Continue
40    }
41
42    /// Called when a message ends (UNT segment).
43    fn on_message_end(&mut self, _unt: &RawSegment) {}
44
45    /// Called when an interchange ends (UNZ segment).
46    fn on_interchange_end(&mut self, _unz: &RawSegment) {}
47
48    /// Called when a parsing error occurs.
49    ///
50    /// Return `Control::Continue` to attempt recovery, or
51    /// `Control::Stop` to abort parsing.
52    fn on_error(&mut self, _error: ParseError) -> Control {
53        Control::Stop
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use edifact_primitives::SegmentPosition;
61
62    /// A test handler that records all events.
63    struct RecordingHandler {
64        events: Vec<String>,
65    }
66
67    impl RecordingHandler {
68        fn new() -> Self {
69            Self { events: Vec::new() }
70        }
71    }
72
73    impl EdifactHandler for RecordingHandler {
74        fn on_delimiters(&mut self, _delimiters: &EdifactDelimiters, explicit_una: bool) {
75            self.events
76                .push(format!("delimiters(una={})", explicit_una));
77        }
78
79        fn on_interchange_start(&mut self, unb: &RawSegment) -> Control {
80            self.events.push(format!("interchange_start({})", unb.id));
81            Control::Continue
82        }
83
84        fn on_message_start(&mut self, unh: &RawSegment) -> Control {
85            self.events.push(format!("message_start({})", unh.id));
86            Control::Continue
87        }
88
89        fn on_segment(&mut self, segment: &RawSegment) -> Control {
90            self.events.push(format!("segment({})", segment.id));
91            Control::Continue
92        }
93
94        fn on_message_end(&mut self, unt: &RawSegment) {
95            self.events.push(format!("message_end({})", unt.id));
96        }
97
98        fn on_interchange_end(&mut self, unz: &RawSegment) {
99            self.events.push(format!("interchange_end({})", unz.id));
100        }
101    }
102
103    #[test]
104    fn test_default_handler_compiles() {
105        struct EmptyHandler;
106        impl EdifactHandler for EmptyHandler {}
107
108        let mut handler = EmptyHandler;
109        let pos = SegmentPosition::new(1, 0, 0);
110        let seg = RawSegment::new("UNB", vec![], pos);
111
112        // All defaults should work
113        handler.on_delimiters(&EdifactDelimiters::default(), false);
114        assert_eq!(handler.on_interchange_start(&seg), Control::Continue);
115        assert_eq!(handler.on_message_start(&seg), Control::Continue);
116        assert_eq!(handler.on_segment(&seg), Control::Continue);
117        handler.on_message_end(&seg);
118        handler.on_interchange_end(&seg);
119    }
120
121    #[test]
122    fn test_recording_handler() {
123        let mut handler = RecordingHandler::new();
124        let pos = SegmentPosition::new(1, 0, 0);
125
126        handler.on_delimiters(&EdifactDelimiters::default(), true);
127        handler.on_interchange_start(&RawSegment::new("UNB", vec![], pos));
128        handler.on_segment(&RawSegment::new("UNB", vec![], pos));
129
130        assert_eq!(handler.events.len(), 3);
131        assert_eq!(handler.events[0], "delimiters(una=true)");
132        assert_eq!(handler.events[1], "interchange_start(UNB)");
133        assert_eq!(handler.events[2], "segment(UNB)");
134    }
135
136    #[test]
137    fn test_handler_stop_control() {
138        struct StopOnSecondSegment {
139            count: usize,
140        }
141        impl EdifactHandler for StopOnSecondSegment {
142            fn on_segment(&mut self, _segment: &RawSegment) -> Control {
143                self.count += 1;
144                if self.count >= 2 {
145                    Control::Stop
146                } else {
147                    Control::Continue
148                }
149            }
150        }
151
152        let mut handler = StopOnSecondSegment { count: 0 };
153        let pos = SegmentPosition::new(1, 0, 1);
154
155        assert_eq!(
156            handler.on_segment(&RawSegment::new("BGM", vec![], pos)),
157            Control::Continue
158        );
159        assert_eq!(
160            handler.on_segment(&RawSegment::new("DTM", vec![], pos)),
161            Control::Stop
162        );
163    }
164}