1use crate::{EdifactError, Segment};
9use std::io::Read;
10use std::str::FromStr;
11
12pub trait EdifactDeserialize: Sized {
19 fn edifact_deserialize(segments: &[Segment<'_>]) -> Result<Self, EdifactError>;
24
25 fn edifact_deserialize_owned(segments: &[crate::OwnedSegment]) -> Result<Self, EdifactError> {
43 let borrowed: Vec<Segment<'_>> = segments.iter().map(|s| s.as_borrowed()).collect();
44 Self::edifact_deserialize(&borrowed)
45 }
46}
47
48pub trait EdifactCompositeDeserialize: Sized {
53 fn edifact_deserialize_composite(composite: CompositeElement<'_>)
55 -> Result<Self, EdifactError>;
56}
57
58impl EdifactCompositeDeserialize for Vec<String> {
59 fn edifact_deserialize_composite(
60 composite: CompositeElement<'_>,
61 ) -> Result<Self, EdifactError> {
62 Ok(composite.iter().map(str::to_owned).collect())
63 }
64}
65
66pub trait EdifactSegmentTag {
71 const SEGMENT_TAG: &'static str;
73
74 const QUALIFIER_PATTERN: Option<&'static str> = None;
80
81 fn matches_qualifier(seg: &Segment<'_>) -> bool {
83 match Self::QUALIFIER_PATTERN {
84 Some(pattern) => seg
85 .element_str(0)
86 .is_some_and(|q| qualifier_matches_pattern(q, pattern)),
87 None => true,
88 }
89 }
90
91 fn matches_segment(seg: &Segment<'_>) -> bool {
96 seg.tag == Self::SEGMENT_TAG && Self::matches_qualifier(seg)
97 }
98
99 fn matches_owned_segment(seg: &crate::OwnedSegment) -> bool {
103 if seg.tag != Self::SEGMENT_TAG {
104 return false;
105 }
106 match Self::QUALIFIER_PATTERN {
107 None => true,
108 Some(pattern) => {
109 let q = seg
110 .elements
111 .first()
112 .and_then(|e| e.components.first())
113 .map(|c| c.as_str())
114 .unwrap_or("");
115 qualifier_matches_pattern(q, pattern)
116 }
117 }
118 }
119}
120
121impl<T> EdifactDeserialize for Vec<T>
126where
127 T: EdifactDeserialize + EdifactSegmentTag,
128{
129 fn edifact_deserialize(segments: &[Segment<'_>]) -> Result<Self, EdifactError> {
130 segments
131 .iter()
132 .filter(|s| T::matches_segment(s))
133 .map(|seg| T::edifact_deserialize(std::slice::from_ref(seg)))
134 .collect()
135 }
136
137 fn edifact_deserialize_owned(segments: &[crate::OwnedSegment]) -> Result<Self, EdifactError> {
138 segments
139 .iter()
140 .filter(|s| T::matches_owned_segment(s))
141 .map(|seg| T::edifact_deserialize_owned(std::slice::from_ref(seg)))
142 .collect()
143 }
144}
145
146pub fn deserialize<T: EdifactDeserialize>(input: &[u8]) -> Result<T, EdifactError> {
156 let segments: Vec<Segment<'_>> = crate::from_bytes(input).collect::<Result<_, _>>()?;
157 T::edifact_deserialize(&segments)
158}
159
160pub fn deserialize_first_streaming<T>(input: &[u8]) -> Result<T, EdifactError>
165where
166 T: EdifactDeserialize + EdifactSegmentTag,
167{
168 for segment in crate::from_bytes(input) {
169 let segment = segment?;
170 if T::matches_segment(&segment) {
171 return T::edifact_deserialize(std::slice::from_ref(&segment));
172 }
173 }
174
175 Err(EdifactError::MissingSegment {
176 tag: T::SEGMENT_TAG.to_owned(),
177 expected_position: "any position in input".to_owned(),
178 })
179}
180
181pub fn deserialize_all_streaming<T>(input: &[u8]) -> Result<Vec<T>, EdifactError>
185where
186 T: EdifactDeserialize + EdifactSegmentTag,
187{
188 let mut out = Vec::new();
189 for segment in crate::from_bytes(input) {
190 let segment = segment?;
191 if T::matches_segment(&segment) {
192 out.push(T::edifact_deserialize(std::slice::from_ref(&segment))?);
193 }
194 }
195 Ok(out)
196}
197
198pub fn deserialize_first_from_reader<T, R>(reader: R) -> Result<T, EdifactError>
202where
203 T: EdifactDeserialize + EdifactSegmentTag,
204 R: Read,
205{
206 for segment in crate::from_reader_iter(reader) {
207 let segment = segment?;
208 if !T::matches_owned_segment(&segment) {
210 continue;
211 }
212 return T::edifact_deserialize_owned(std::slice::from_ref(&segment));
213 }
214
215 Err(EdifactError::MissingSegment {
216 tag: T::SEGMENT_TAG.to_owned(),
217 expected_position: "any position in input".to_owned(),
218 })
219}
220
221pub fn deserialize_all_from_reader<T, R>(reader: R) -> Result<Vec<T>, EdifactError>
223where
224 T: EdifactDeserialize + EdifactSegmentTag,
225 R: Read,
226{
227 let mut out = Vec::new();
228 for segment in crate::from_reader_iter(reader) {
229 let segment = segment?;
230 if !T::matches_owned_segment(&segment) {
232 continue;
233 }
234 out.push(T::edifact_deserialize_owned(std::slice::from_ref(&segment))?);
235 }
236 Ok(out)
237}
238
239pub fn deserialize_str<T: EdifactDeserialize>(input: &str) -> Result<T, EdifactError> {
241 deserialize(input.as_bytes())
242}
243
244pub fn find_segment<'s, 'd>(segments: &'s [Segment<'d>], tag: &str) -> Option<&'s Segment<'d>> {
248 segments.iter().find(|s| s.tag == tag)
249}
250
251pub fn find_segments_iter<'s, 'd: 's>(
253 segments: &'s [Segment<'d>],
254 tag: &'s str,
255) -> impl Iterator<Item = &'s Segment<'d>> {
256 segments.iter().filter(move |s| s.tag == tag)
257}
258
259pub fn find_qualified_segment<'s, 'd>(
261 segments: &'s [Segment<'d>],
262 tag: &str,
263 qualifier: &str,
264) -> Option<&'s Segment<'d>> {
265 segments
266 .iter()
267 .find(|s| s.tag == tag && s.element_str(0).unwrap_or("") == qualifier)
268}
269
270pub fn find_segment_typed<'s, 'd, T>(segments: &'s [Segment<'d>]) -> Option<&'s Segment<'d>>
272where
273 T: EdifactSegmentTag,
274{
275 segments.iter().find(|s| T::matches_segment(s))
276}
277
278pub fn find_segments_typed<'s, 'd: 's, T>(
280 segments: &'s [Segment<'d>],
281) -> impl Iterator<Item = &'s Segment<'d>>
282where
283 T: EdifactSegmentTag,
284{
285 segments.iter().filter(|s| T::matches_segment(s))
286}
287
288pub fn contiguous_groups_by_qualifier<'s, 'd, T>(
293 segments: &'s [Segment<'d>],
294) -> Vec<&'s [Segment<'d>]>
295where
296 T: EdifactSegmentTag,
297{
298 let mut groups = Vec::new();
299 let mut idx = 0;
300 while idx < segments.len() {
301 if T::matches_segment(&segments[idx]) {
302 let start = idx;
303 idx += 1;
304 while idx < segments.len() && T::matches_segment(&segments[idx]) {
305 idx += 1;
306 }
307 groups.push(&segments[start..idx]);
308 } else {
309 idx += 1;
310 }
311 }
312 groups
313}
314
315pub fn contiguous_groups_iter<'s, 'd, T>(
332 segments: &'s [Segment<'d>],
333) -> impl Iterator<Item = &'s [Segment<'d>]> + 's
334where
335 T: EdifactSegmentTag,
336{
337 let mut idx = 0;
338 let len = segments.len();
339 std::iter::from_fn(move || {
340 while idx < len && !T::matches_segment(&segments[idx]) {
342 idx += 1;
343 }
344 if idx >= len {
345 return None;
346 }
347 let start = idx;
348 idx += 1;
349 while idx < len && T::matches_segment(&segments[idx]) {
350 idx += 1;
351 }
352 Some(&segments[start..idx])
353 })
354}
355
356pub fn groups_are_contiguous_by_qualifier<T>(segments: &[Segment<'_>]) -> bool
358where
359 T: EdifactSegmentTag,
360{
361 let mut seen_match = false;
362 let mut seen_gap_after_match = false;
363
364 for seg in segments {
365 if T::matches_segment(seg) {
366 if seen_gap_after_match {
367 return false;
368 }
369 seen_match = true;
370 } else if seen_match {
371 seen_gap_after_match = true;
372 }
373 }
374
375 true
376}
377
378pub fn qualifier_matches_pattern(value: &str, pattern: &str) -> bool {
387 if pattern.is_empty() {
388 return value.is_empty();
389 }
390
391 if !pattern.contains('*') {
392 return value == pattern;
393 }
394
395 if let Some((prefix, suffix)) = pattern.split_once('*') {
397 if !pattern[prefix.len() + 1..].contains('*') {
399 return value.len() >= prefix.len() + suffix.len()
400 && value.starts_with(prefix)
401 && value.ends_with(suffix)
402 && {
403 let mid_start = prefix.len();
405 let mid_end = value.len().saturating_sub(suffix.len());
406 mid_start <= mid_end
407 };
408 }
409 }
410
411 let parts: smallvec::SmallVec<[&str; 4]> = pattern.split('*').collect();
413 let prefix = parts[0];
414 let suffix = parts[parts.len() - 1];
415
416 if !value.starts_with(prefix) || !value.ends_with(suffix) {
417 return false;
418 }
419
420 let mid_start = prefix.len();
421 let mid_end = value.len().saturating_sub(suffix.len());
422
423 if mid_start > mid_end {
424 return parts[1..parts.len() - 1].iter().all(|p| p.is_empty());
425 }
426
427 let mut remaining = &value[mid_start..mid_end];
428
429 for part in &parts[1..parts.len() - 1] {
430 if part.is_empty() {
431 continue;
432 }
433 match remaining.find(part) {
434 Some(idx) => remaining = &remaining[idx + part.len()..],
435 None => return false,
436 }
437 }
438
439 true
440}
441
442#[inline]
444pub fn element_str<'s>(seg: &'s Segment<'_>, idx: usize) -> &'s str {
445 seg.element_str(idx).unwrap_or("")
446}
447
448pub fn required_element<'a>(seg: &'a Segment<'_>, idx: usize) -> Result<&'a str, EdifactError> {
464 seg.text_element(idx)
465}
466
467pub fn optional_element<'a>(seg: &'a Segment<'_>, idx: usize) -> Option<&'a str> {
473 SegmentAccessor::optional_element(seg, idx)
474}
475
476pub fn required_component<'a>(
494 seg: &'a Segment<'_>,
495 elem_idx: usize,
496 comp_idx: usize,
497) -> Result<&'a str, EdifactError> {
498 seg.required_composite(elem_idx, comp_idx)
499}
500
501pub fn optional_component<'a>(seg: &'a Segment<'_>, elem_idx: usize, comp_idx: usize) -> Option<&'a str> {
507 SegmentAccessor::get_component(seg, elem_idx, comp_idx)
508}
509
510pub fn get_components_iter<'a>(
514 seg: &'a Segment<'_>,
515 idx: usize,
516) -> impl Iterator<Item = &'a str> {
517 seg.elements
518 .get(idx)
519 .into_iter()
520 .flat_map(|elem| elem.components.iter().map(|c| c.as_ref()))
521}
522
523pub struct CompositeElement<'a> {
525 components: &'a [std::borrow::Cow<'a, str>],
526}
527
528impl<'a> CompositeElement<'a> {
529 pub fn get(&self, i: usize) -> Option<&'a str> {
531 self.components.get(i).map(|c| c.as_ref())
532 }
533
534 pub fn get_or_empty(&self, i: usize) -> &'a str {
536 self.get(i).unwrap_or("")
537 }
538
539 pub fn len(&self) -> usize {
541 self.components.len()
542 }
543
544 pub fn is_empty(&self) -> bool {
546 self.components.is_empty()
547 }
548
549 pub fn iter(&self) -> impl Iterator<Item = &'a str> {
551 self.components.iter().map(|c| c.as_ref())
552 }
553
554 pub fn from_slice(components: &'a [std::borrow::Cow<'a, str>]) -> Self {
559 Self { components }
560 }
561}
562
563pub fn composite_element<'a>(seg: &'a Segment<'_>, idx: usize) -> Option<CompositeElement<'a>> {
565 seg.elements.get(idx).map(|elem| CompositeElement {
566 components: &elem.components,
567 })
568}
569
570pub fn find_segment_owned<'s>(
577 segments: &'s [crate::OwnedSegment],
578 tag: &str,
579) -> Option<&'s crate::OwnedSegment> {
580 segments.iter().find(|s| s.tag == tag)
581}
582
583pub fn find_qualified_segment_owned<'s>(
591 segments: &'s [crate::OwnedSegment],
592 tag: &str,
593 qualifier: &str,
594) -> Option<&'s crate::OwnedSegment> {
595 segments.iter().find(|s| {
596 s.tag == tag && s.element_str(0).unwrap_or("") == qualifier
597 })
598}
599
600pub trait SegmentAccessor<'a> {
602 fn get_element(&'a self, idx: usize) -> Option<&'a str>;
604 fn get_component(&'a self, elem: usize, comp: usize) -> Option<&'a str>;
606 fn get_composite(&'a self, idx: usize) -> Option<CompositeElement<'a>>;
608
609 fn text_element(&'a self, idx: usize) -> Result<&'a str, EdifactError>;
611 fn optional_element(&'a self, idx: usize) -> Option<&'a str>;
613 fn code_element<T: FromStr>(&'a self, idx: usize) -> Result<T, EdifactError>;
615 fn required_composite(&'a self, elem: usize, comp: usize) -> Result<&'a str, EdifactError>;
617 fn repeating_components(
623 &'a self,
624 elem: usize,
625 start_idx: usize,
626 count: usize,
627 ) -> Result<Vec<&'a str>, EdifactError> {
628 self.repeating_components_iter(elem, start_idx, count).collect()
631 }
632
633 fn repeating_components_iter(
638 &'a self,
639 elem: usize,
640 start_idx: usize,
641 count: usize,
642 ) -> impl Iterator<Item = Result<&'a str, EdifactError>> + 'a;
643}
644
645impl<'s, 'd> SegmentAccessor<'s> for Segment<'d>
646where
647 'd: 's,
648{
649 fn get_element(&'s self, idx: usize) -> Option<&'s str> {
650 self.element_str(idx).filter(|s| !s.is_empty())
651 }
652
653 fn get_component(&'s self, elem: usize, comp: usize) -> Option<&'s str> {
654 self.elements
655 .get(elem)
656 .and_then(|e| e.get_component(comp))
657 .filter(|s| !s.is_empty())
658 }
659
660 fn get_composite(&'s self, idx: usize) -> Option<CompositeElement<'s>> {
661 composite_element(self, idx)
662 }
663
664 fn text_element(&'s self, idx: usize) -> Result<&'s str, EdifactError> {
665 <Self as SegmentAccessor>::get_element(self, idx).ok_or_else(|| {
666 EdifactError::MissingRequiredElement {
667 tag: self.tag.to_owned(),
668 element_index: idx,
669 }
670 })
671 }
672
673 fn optional_element(&'s self, idx: usize) -> Option<&'s str> {
674 <Self as SegmentAccessor>::get_element(self, idx)
675 }
676
677 fn code_element<T: FromStr>(&'s self, idx: usize) -> Result<T, EdifactError> {
678 let raw = self.text_element(idx)?;
679 raw.parse::<T>().map_err(|_| EdifactError::InvalidText {
680 offset: self.element_span(idx).map(|s| s.start).unwrap_or(self.span.start),
681 })
682 }
683
684 fn required_composite(&'s self, elem: usize, comp: usize) -> Result<&'s str, EdifactError> {
685 match self.elements.get(elem) {
686 None => Err(EdifactError::MissingRequiredElement {
687 tag: self.tag.to_owned(),
688 element_index: elem,
689 }),
690 Some(e) => e
691 .get_component(comp)
692 .filter(|s| !s.is_empty())
693 .ok_or_else(|| EdifactError::MissingRequiredComponent {
694 tag: self.tag.to_owned(),
695 element_index: elem,
696 component_index: comp,
697 }),
698 }
699 }
700
701 fn repeating_components_iter(
702 &'s self,
703 elem: usize,
704 start_idx: usize,
705 count: usize,
706 ) -> impl Iterator<Item = Result<&'s str, EdifactError>> + 's {
707 let tag = self.tag;
708 let element_exists = self.elements.get(elem).is_some();
709 let components = self
710 .elements
711 .get(elem)
712 .map(|e| e.components.as_slice())
713 .unwrap_or(&[]);
714 (start_idx..start_idx + count).map(move |idx| {
715 components
716 .get(idx)
717 .map(|c| c.as_ref())
718 .filter(|s| !s.is_empty())
719 .ok_or_else(|| {
720 if element_exists {
721 EdifactError::MissingRequiredComponent {
722 tag: tag.to_owned(),
723 element_index: elem,
724 component_index: idx,
725 }
726 } else {
727 EdifactError::MissingRequiredElement {
728 tag: tag.to_owned(),
729 element_index: elem,
730 }
731 }
732 })
733 })
734 }
735}
736
737pub struct MessageWindowsSliceIter<'a> {
748 inner: crate::FromBytesIter<'a>,
749 buf: Vec<crate::Segment<'a>>,
750 in_message: bool,
751 done: bool,
752}
753
754impl<'a> MessageWindowsSliceIter<'a> {
755 fn new(inner: crate::FromBytesIter<'a>) -> Self {
756 Self {
757 inner,
758 buf: Vec::new(),
759 in_message: false,
760 done: false,
761 }
762 }
763}
764
765impl<'a> Iterator for MessageWindowsSliceIter<'a> {
766 type Item = Result<Vec<crate::Segment<'a>>, EdifactError>;
767
768 fn next(&mut self) -> Option<Self::Item> {
769 if self.done {
770 return None;
771 }
772 loop {
773 let segment = match self.inner.next() {
774 Some(Ok(s)) => s,
775 Some(Err(e)) => {
776 self.done = true;
777 return Some(Err(e));
778 }
779 None => {
780 self.done = true;
781 if self.in_message && !self.buf.is_empty() {
782 self.in_message = false;
783 let offset = self.buf.last().map(|s| s.span.end).unwrap_or(0);
784 return Some(Err(EdifactError::UnexpectedEof { offset }));
785 }
786 return None;
787 }
788 };
789
790 match segment.tag {
791 "UNH" => {
792 if self.in_message {
793 self.buf.clear();
794 self.in_message = false;
795 self.done = true;
796 let offset = segment.span.start;
797 return Some(Err(EdifactError::InvalidSegmentForMessage {
798 tag: "UNH".to_owned(),
799 message_type: "ENVELOPE".to_owned(),
800 offset,
801 }));
802 }
803 self.buf.clear();
804 self.in_message = true;
805 self.buf.push(segment);
806 }
807 "UNT" if self.in_message => {
808 self.buf.push(segment);
809 self.in_message = false;
810 return Some(Ok(std::mem::take(&mut self.buf)));
811 }
812 _ if self.in_message => {
813 self.buf.push(segment);
814 }
815 _ => {
816 }
818 }
819 }
820 }
821}
822
823pub struct MessageWindowsIter<I> {
844 inner: I,
845 buf: Vec<crate::OwnedSegment>,
846 in_message: bool,
847 done: bool,
850}
851
852impl<I: Iterator<Item = Result<crate::OwnedSegment, EdifactError>>> MessageWindowsIter<I> {
853 pub fn new(inner: I) -> Self {
855 Self {
856 inner,
857 buf: Vec::new(),
858 in_message: false,
859 done: false,
860 }
861 }
862}
863
864impl<I: Iterator<Item = Result<crate::OwnedSegment, EdifactError>>> Iterator
865 for MessageWindowsIter<I>
866{
867 type Item = Result<Vec<crate::OwnedSegment>, EdifactError>;
868
869 fn next(&mut self) -> Option<Self::Item> {
870 if self.done {
871 return None;
872 }
873 loop {
874 let segment = match self.inner.next() {
875 Some(Ok(s)) => s,
876 Some(Err(e)) => {
877 self.done = true;
878 return Some(Err(e));
879 }
880 None => {
881 self.done = true;
882 if self.in_message && !self.buf.is_empty() {
885 self.in_message = false;
886 let offset = self.buf.last().map(|s| s.span.end).unwrap_or(0);
887 return Some(Err(EdifactError::UnexpectedEof { offset }));
888 }
889 return None;
890 }
891 };
892
893 match segment.tag.as_str() {
894 "UNH" => {
895 if self.in_message {
896 self.buf.clear();
898 self.in_message = false;
899 self.done = true;
900 let offset = segment.span.start;
901 return Some(Err(EdifactError::InvalidSegmentForMessage {
902 tag: "UNH".to_owned(),
903 message_type: "ENVELOPE".to_owned(),
904 offset,
905 }));
906 }
907 self.buf.clear();
908 self.in_message = true;
909 self.buf.push(segment);
910 }
911 "UNT" if self.in_message => {
912 self.buf.push(segment);
913 self.in_message = false;
914 return Some(Ok(std::mem::take(&mut self.buf)));
915 }
916 _ if self.in_message => {
917 self.buf.push(segment);
918 }
919 _ => {
920 }
922 }
923 }
924 }
925}
926
927pub fn message_windows_bytes(input: &[u8]) -> MessageWindowsSliceIter<'_> {
950 MessageWindowsSliceIter::new(crate::from_bytes(input))
951}
952
953pub fn message_windows_from_reader<R: Read>(
959 reader: R,
960) -> MessageWindowsIter<crate::FromReaderIter<R>> {
961 MessageWindowsIter::new(crate::from_reader_iter(reader))
962}
963
964pub fn deserialize_messages_from_reader<T, R>(
983 reader: R,
984) -> impl Iterator<Item = Result<T, EdifactError>>
985where
986 T: EdifactDeserialize,
987 R: Read,
988{
989 message_windows_from_reader(reader).map(|window| {
990 let window = window?;
991 T::edifact_deserialize_owned(&window)
992 })
993}
994
995pub fn deserialize_messages_bytes<T>(
997 input: &[u8],
998) -> impl Iterator<Item = Result<T, EdifactError>> + '_
999where
1000 T: EdifactDeserialize,
1001{
1002 message_windows_bytes(input).map(|window| {
1003 let window = window?;
1004 T::edifact_deserialize(&window)
1005 })
1006}
1007
1008pub fn message_type_from_window<'a>(window: &'a [Segment<'a>]) -> Option<&'a str> {
1029 window
1030 .iter()
1031 .find(|s| s.tag == "UNH")
1032 .and_then(|unh| unh.get_element(1))
1033 .and_then(|e| e.get_component(0))
1034}
1035
1036pub struct DispatchedMessage {
1040 pub message_type: String,
1042 value: Box<dyn std::any::Any + Send + Sync>,
1043}
1044
1045impl DispatchedMessage {
1046 pub fn downcast<T: std::any::Any + Send + Sync + 'static>(&self) -> Option<&T> {
1050 self.value.downcast_ref::<T>()
1051 }
1052}
1053
1054impl std::fmt::Debug for DispatchedMessage {
1055 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1056 f.debug_struct("DispatchedMessage")
1057 .field("message_type", &self.message_type)
1058 .finish_non_exhaustive()
1059 }
1060}
1061
1062type DispatchHandlerFn =
1063 Box<dyn for<'a> Fn(&[Segment<'a>]) -> Result<Box<dyn std::any::Any + Send + Sync>, EdifactError> + Send + Sync>;
1064
1065type FallbackHandlerFn =
1066 Box<dyn for<'a> Fn(&[Segment<'a>], &str) -> Result<Box<dyn std::any::Any + Send + Sync>, EdifactError> + Send + Sync>;
1067
1068pub struct MessageDispatch {
1093 handlers: Vec<(String, DispatchHandlerFn)>,
1094 fallback: Option<FallbackHandlerFn>,
1095}
1096
1097impl Default for MessageDispatch {
1098 fn default() -> Self {
1099 Self::new()
1100 }
1101}
1102
1103impl MessageDispatch {
1104 pub fn new() -> Self {
1106 Self {
1107 handlers: Vec::new(),
1108 fallback: None,
1109 }
1110 }
1111
1112 pub fn on<T, F>(mut self, message_type: &str, handler: F) -> Self
1117 where
1118 T: std::any::Any + Send + Sync + 'static,
1119 F: for<'a> Fn(&[Segment<'a>]) -> Result<T, EdifactError> + Send + Sync + 'static,
1120 {
1121 let erased: DispatchHandlerFn = Box::new(move |segs| {
1122 let val = handler(segs)?;
1123 Ok(Box::new(val) as Box<dyn std::any::Any + Send + Sync>)
1124 });
1125 self.handlers.push((message_type.to_owned(), erased));
1126 self
1127 }
1128
1129 pub fn fallback<T, F>(mut self, handler: F) -> Self
1134 where
1135 T: std::any::Any + Send + Sync + 'static,
1136 F: for<'a> Fn(&[Segment<'a>], &str) -> Result<T, EdifactError> + Send + Sync + 'static,
1137 {
1138 let erased: FallbackHandlerFn = Box::new(move |segs, mt| {
1139 let val = handler(segs, mt)?;
1140 Ok(Box::new(val) as Box<dyn std::any::Any + Send + Sync>)
1141 });
1142 self.fallback = Some(erased);
1143 self
1144 }
1145
1146 pub fn dispatch(&self, window: &[Segment<'_>]) -> Result<DispatchedMessage, EdifactError> {
1151 let message_type = window
1152 .iter()
1153 .find(|s| s.tag == "UNH")
1154 .and_then(|unh| unh.get_element(1))
1155 .and_then(|e| e.get_component(0))
1156 .map(|s| s.to_owned())
1157 .ok_or_else(|| EdifactError::MissingSegment {
1158 tag: "UNH".to_owned(),
1159 expected_position: "first segment of message window".to_owned(),
1160 })?;
1161
1162 for (mt, handler) in &self.handlers {
1163 if *mt == message_type {
1164 let value = handler(window)?;
1165 return Ok(DispatchedMessage { message_type, value });
1166 }
1167 }
1168
1169 if let Some(fallback) = &self.fallback {
1170 let value = fallback(window, &message_type)?;
1171 return Ok(DispatchedMessage { message_type, value });
1172 }
1173
1174 Err(EdifactError::UnexpectedMessageType {
1175 message_type,
1176 })
1177 }
1178
1179 pub fn dispatch_all_from_bytes<'a>(
1184 &'a self,
1185 input: &'a [u8],
1186 ) -> impl Iterator<Item = Result<DispatchedMessage, EdifactError>> + 'a {
1187 message_windows_bytes(input).map(move |window| {
1188 let window = window?;
1189 self.dispatch(&window)
1190 })
1191 }
1192
1193 pub fn dispatch_all_from_reader<R: Read + 'static>(
1200 &self,
1201 reader: R,
1202 ) -> impl Iterator<Item = Result<DispatchedMessage, EdifactError>> + '_ {
1203 message_windows_from_reader(reader).map(|window| {
1204 let window = window?;
1205 let borrowed: Vec<Segment<'_>> = window.iter().map(|s| s.as_borrowed()).collect();
1206 self.dispatch(&borrowed)
1207 })
1208 }
1209}
1210
1211#[cfg(test)]
1212mod tests {
1213 use super::*;
1214
1215 #[derive(Debug, PartialEq)]
1217 struct BgmSegment {
1218 doc_name_code: String,
1219 pruef_id: String,
1220 msg_function: Option<String>,
1221 }
1222
1223 impl EdifactSegmentTag for BgmSegment {
1224 const SEGMENT_TAG: &'static str = "BGM";
1225 }
1226
1227 struct NadM;
1228
1229 impl EdifactSegmentTag for NadM {
1230 const SEGMENT_TAG: &'static str = "NAD";
1231 const QUALIFIER_PATTERN: Option<&'static str> = Some("M*");
1232 }
1233
1234 struct NadWildcard;
1235
1236 impl EdifactSegmentTag for NadWildcard {
1237 const SEGMENT_TAG: &'static str = "NAD";
1238 const QUALIFIER_PATTERN: Option<&'static str> = Some("M*");
1239 }
1240
1241 impl EdifactDeserialize for BgmSegment {
1242 fn edifact_deserialize(segments: &[Segment<'_>]) -> Result<Self, EdifactError> {
1243 let seg = find_segment(segments, "BGM").ok_or_else(|| {
1244 EdifactError::MissingRequiredElement {
1245 tag: "BGM".to_owned(),
1246 element_index: 0,
1247 }
1248 })?;
1249 Ok(Self {
1250 doc_name_code: element_str(seg, 0).to_owned(),
1251 pruef_id: element_str(seg, 1).to_owned(),
1252 msg_function: seg
1253 .element_str(2)
1254 .filter(|s| !s.is_empty())
1255 .map(str::to_owned),
1256 })
1257 }
1258 }
1259
1260 #[test]
1261 fn deserialize_single_segment() {
1262 let input = b"BGM+E03+11042+9'";
1263 let bgm: BgmSegment = deserialize(input).unwrap();
1264 assert_eq!(bgm.doc_name_code, "E03");
1265 assert_eq!(bgm.pruef_id, "11042");
1266 assert_eq!(bgm.msg_function, Some("9".to_owned()));
1267 }
1268
1269 #[test]
1270 fn streaming_deserialize_first_from_bytes() {
1271 let input = b"UNH+1+ORDERS:D:11A:UN'BGM+E03+11042+9'UNT+3+1'";
1272 let bgm: BgmSegment = deserialize_first_streaming(input).unwrap();
1273 assert_eq!(bgm.pruef_id, "11042");
1274 }
1275
1276 #[test]
1277 fn streaming_deserialize_all_from_bytes() {
1278 let input = b"BGM+E03+11042+9'RFF+AA:1'BGM+E01+11043+9'";
1279 let bgms: Vec<BgmSegment> = deserialize_all_streaming(input).unwrap();
1280 assert_eq!(bgms.len(), 2);
1281 assert_eq!(bgms[0].pruef_id, "11042");
1282 assert_eq!(bgms[1].pruef_id, "11043");
1283 }
1284
1285 #[test]
1286 fn streaming_deserialize_first_from_reader() {
1287 let input = std::io::Cursor::new(b"UNH+1+ORDERS:D:11A:UN'BGM+E03+11042+9'UNT+3+1'".to_vec());
1288 let bgm: BgmSegment = deserialize_first_from_reader(input).unwrap();
1289 assert_eq!(bgm.pruef_id, "11042");
1290 }
1291
1292 #[test]
1293 fn streaming_deserialize_all_from_reader() {
1294 let input = std::io::Cursor::new(b"BGM+E03+11042+9'BGM+E01+11043+9'".to_vec());
1295 let bgms: Vec<BgmSegment> = deserialize_all_from_reader(input).unwrap();
1296 assert_eq!(bgms.len(), 2);
1297 assert_eq!(bgms[0].pruef_id, "11042");
1298 assert_eq!(bgms[1].pruef_id, "11043");
1299 }
1300
1301 #[test]
1302 fn missing_segment_returns_error() {
1303 let input = b"DTM+137:20230401:102'";
1304 let result: Result<BgmSegment, _> = deserialize(input);
1305 assert!(result.is_err());
1306 }
1307
1308 #[test]
1309 fn vec_collects_all_matching_segments() {
1310 let input = b"DTM+137:20230401:102'BGM+E03+11042+9'BGM+E01+11043+9'";
1311 let bgms: Vec<BgmSegment> = deserialize(input).unwrap();
1312 assert_eq!(bgms.len(), 2);
1313 assert_eq!(bgms[0].pruef_id, "11042");
1314 assert_eq!(bgms[1].pruef_id, "11043");
1315 }
1316
1317 #[test]
1318 fn find_qualified_segment_matches_qualifier() {
1319 let input = b"NAD+MS+9900001+293'NAD+MR+9900002+293'";
1320 let segments: Vec<Segment<'_>> =
1321 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1322 let nad_ms = find_qualified_segment(&segments, "NAD", "MS");
1323 let nad_mr = find_qualified_segment(&segments, "NAD", "MR");
1324 assert!(nad_ms.is_some());
1325 assert!(nad_mr.is_some());
1326 assert_eq!(element_str(nad_ms.unwrap(), 0), "MS");
1327 assert_eq!(element_str(nad_mr.unwrap(), 0), "MR");
1328 }
1329
1330 #[test]
1331 fn round_trip_str_api() {
1332 let input = "BGM+E03+11042+9'";
1333 let bgm: BgmSegment = deserialize_str(input).unwrap();
1334 assert_eq!(bgm.pruef_id, "11042");
1335 }
1336
1337 #[test]
1338 fn required_element_extraction() {
1339 let input = b"BGM+E03+11042+9'";
1340 let segments: Vec<Segment<'_>> =
1341 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1342 let seg = &segments[0];
1343
1344 assert_eq!(required_element(seg, 0).unwrap(), "E03");
1345 assert_eq!(required_element(seg, 1).unwrap(), "11042");
1346 assert!(required_element(seg, 5).is_err());
1348 }
1349
1350 #[test]
1351 fn optional_element_extraction() {
1352 let input = b"BGM+E03+11042+9'BGM+E01++absent'";
1353 let segments: Vec<Segment<'_>> =
1354 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1355
1356 assert_eq!(optional_element(&segments[0], 0), Some("E03"));
1358 assert_eq!(optional_element(&segments[0], 1), Some("11042"));
1359 assert_eq!(optional_element(&segments[0], 5), None);
1360
1361 assert_eq!(optional_element(&segments[1], 1), None);
1363 }
1364
1365 #[test]
1366 fn component_extraction() {
1367 let input = b"UNB+UNOA:1+SENDER+RECEIVER+200101:0900+1'";
1368 let segments: Vec<Segment<'_>> =
1369 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1370 let seg = &segments[0];
1371
1372 assert_eq!(required_component(seg, 0, 0).unwrap(), "UNOA");
1373 assert_eq!(required_component(seg, 0, 1).unwrap(), "1");
1374 assert!(required_component(seg, 0, 5).is_err());
1376 }
1377
1378 #[test]
1379 fn composite_element_helper() {
1380 let input = b"UNB+UNOA:1+SENDER+RECEIVER+200101:0900+1'";
1381 let segments: Vec<Segment<'_>> =
1382 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1383 let seg = &segments[0];
1384
1385 let comp = composite_element(seg, 0).unwrap();
1386 assert_eq!(comp.len(), 2);
1387 assert_eq!(comp.get(0), Some("UNOA"));
1388 assert_eq!(comp.get(1), Some("1"));
1389 assert_eq!(comp.get(5), None);
1390 assert_eq!(comp.get_or_empty(5), "");
1391 }
1392
1393 #[test]
1394 fn get_all_components() {
1395 let input = b"UNB+UNOA:1+SENDER+RECEIVER+200101:0900+1'";
1397 let segments: Vec<Segment<'_>> =
1398 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1399 let seg = &segments[0];
1400
1401 let comps: Vec<&str> = get_components_iter(seg, 0).collect(); assert!(!comps.is_empty(), "Expected components but got empty");
1403 assert_eq!(comps.len(), 2);
1404 assert_eq!(comps[0], "UNOA");
1405 assert_eq!(comps[1], "1");
1406 }
1407
1408 #[test]
1409 fn qualifier_pattern_matching_supports_exact_and_wildcard() {
1410 assert!(qualifier_matches_pattern("MS", "MS"));
1412 assert!(!qualifier_matches_pattern("MS", "M")); assert!(qualifier_matches_pattern("MS", "M*"));
1415 assert!(qualifier_matches_pattern("MRY", "M*Y"));
1416 assert!(!qualifier_matches_pattern("AB", "M*"));
1417 }
1418
1419 #[test]
1421 fn qualifier_matches_pattern_table() {
1422 let cases: &[(&str, &str, bool)] = &[
1424 ("", "", true), ("", "*", true), ("A", "", false), ("", "A", false), ("MS", "MS", true),
1431 ("BY", "BY", true),
1432 ("ms", "MS", false), ("MSX", "MS", false), ("M", "MS", false), ("MS", "M*", true),
1437 ("MULTI", "MUL*", true),
1438 ("AB", "M*", false),
1439 ("", "M*", false), ("MSG", "*G", true),
1442 ("G", "*G", true),
1443 ("MSG", "*X", false),
1444 ("", "*G", false),
1445 ("MRY", "M*Y", true),
1447 ("MAY", "M*Y", true),
1448 ("MY", "M*Y", true), ("MYY", "M*Y", true), ("MAYZ", "M*Y", false),("AB", "M*Y", false),
1452 ("*", "*", true), ("anything", "*", true),
1455 ("", "*", true),
1456 ("ABCDE", "A*C*E", true),
1458 ("ACE", "A*C*E", true), ("AXCYE", "A*C*E", true),
1460 ("ABCDF", "A*C*E", false),
1461 ("AB", "A**B", true), ("AB", "A*B*C", false),
1465 ("XMS", "MS", false),
1467 ];
1468
1469 for (value, pattern, expected) in cases {
1470 let got = qualifier_matches_pattern(value, pattern);
1471 assert_eq!(
1472 got, *expected,
1473 "qualifier_matches_pattern({value:?}, {pattern:?}) expected {expected} but got {got}"
1474 );
1475 }
1476 }
1477
1478 #[test]
1479 fn typed_qualifier_helpers_work() {
1480 let input = b"NAD+MS+9900001+293'NAD+MR+9900002+293'";
1481 let segments: Vec<Segment<'_>> =
1482 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1483
1484 let first = find_segment_typed::<NadM>(&segments).unwrap();
1485 assert_eq!(first.element_str(0), Some("MS"));
1486
1487 let all: Vec<_> = find_segments_typed::<NadWildcard>(&segments).collect();
1488 assert_eq!(all.len(), 2);
1489 }
1490
1491 #[test]
1492 fn segment_accessor_trait_methods_work() {
1493 let input = b"UNB+UNOA:1+SENDER+RECEIVER+200101:0900+1'";
1494 let segments: Vec<Segment<'_>> =
1495 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1496 let seg = &segments[0];
1497
1498 assert_eq!(SegmentAccessor::get_element(seg, 1), Some("SENDER"));
1499 assert_eq!(SegmentAccessor::required_composite(seg, 0, 1).unwrap(), "1");
1500 let parsed: i32 = SegmentAccessor::code_element(seg, 4).unwrap();
1501 assert_eq!(parsed, 1);
1502 let reps = SegmentAccessor::repeating_components(seg, 3, 0, 2).unwrap();
1503 assert_eq!(reps, vec!["200101", "0900"]);
1504 }
1505
1506 #[test]
1507 fn group_helpers_detect_contiguity() {
1508 struct NadAny;
1509 impl EdifactSegmentTag for NadAny {
1510 const SEGMENT_TAG: &'static str = "NAD";
1511 }
1512
1513 let contiguous_input = b"NAD+MS+1'NAD+MR+2'RFF+AA:1'";
1514 let contiguous_segments: Vec<Segment<'_>> = crate::from_bytes(contiguous_input)
1515 .collect::<Result<_, _>>()
1516 .unwrap();
1517 assert!(groups_are_contiguous_by_qualifier::<NadAny>(
1518 &contiguous_segments
1519 ));
1520
1521 let non_contiguous_input = b"NAD+MS+1'RFF+AA:1'NAD+MR+2'";
1522 let non_contiguous_segments: Vec<Segment<'_>> = crate::from_bytes(non_contiguous_input)
1523 .collect::<Result<_, _>>()
1524 .unwrap();
1525 assert!(!groups_are_contiguous_by_qualifier::<NadAny>(
1526 &non_contiguous_segments
1527 ));
1528 }
1529
1530 #[test]
1531 fn group_helpers_collect_contiguous_groups() {
1532 struct NadAny;
1533 impl EdifactSegmentTag for NadAny {
1534 const SEGMENT_TAG: &'static str = "NAD";
1535 }
1536
1537 let input = b"NAD+MS+1'NAD+MR+2'RFF+AA:1'NAD+BY+3'";
1538 let segments: Vec<Segment<'_>> =
1539 crate::from_bytes(input).collect::<Result<_, _>>().unwrap();
1540 let groups = contiguous_groups_by_qualifier::<NadAny>(&segments);
1541
1542 assert_eq!(groups.len(), 2);
1543 assert_eq!(groups[0].len(), 2);
1544 assert_eq!(groups[1].len(), 1);
1545 }
1546
1547 #[test]
1550 fn message_windows_bytes_yields_complete_windows() {
1551 let input = b"UNB+UNOA:1+S+R+200101:0900+1'\
1552 UNH+1+ORDERS:D:96A:UN'\
1553 BGM+220+PO-001+9'\
1554 UNT+3+1'\
1555 UNZ+1+1'";
1556 let windows: Vec<_> = message_windows_bytes(input)
1557 .collect::<Result<_, _>>()
1558 .unwrap();
1559 assert_eq!(windows.len(), 1);
1560 assert_eq!(windows[0][0].tag, "UNH");
1561 assert_eq!(windows[0].last().unwrap().tag, "UNT");
1562 }
1563
1564 #[test]
1565 fn message_windows_truncated_stream_returns_error() {
1566 let input = b"UNH+1+ORDERS:D:96A:UN'BGM+220+PO-001+9'";
1568 let results: Vec<_> = message_windows_bytes(input).collect();
1569 assert_eq!(results.len(), 1);
1570 assert!(
1571 matches!(results[0], Err(EdifactError::UnexpectedEof { .. })),
1572 "expected UnexpectedEof for truncated window, got: {:?}",
1573 results[0]
1574 );
1575 }
1576
1577 #[test]
1578 fn message_windows_subsequent_calls_return_none_after_truncation() {
1579 let input = b"UNH+1+ORDERS:D:96A:UN'BGM+220+PO-001+9'";
1580 let mut iter = message_windows_bytes(input);
1581 assert!(matches!(
1582 iter.next(),
1583 Some(Err(EdifactError::UnexpectedEof { .. }))
1584 ));
1585 assert!(iter.next().is_none());
1587 }
1588
1589 #[test]
1590 fn message_windows_unh_without_unt_before_next_unh_returns_error() {
1591 let input = b"UNH+1+ORDERS:D:96A:UN'BGM+220+PO-001+9'\
1592 UNH+2+ORDERS:D:96A:UN'BGM+220+PO-002+9'UNT+3+2'";
1593 let results: Vec<_> = message_windows_bytes(input).collect();
1594 assert!(
1596 matches!(
1597 results[0],
1598 Err(EdifactError::InvalidSegmentForMessage { ref tag, .. }) if tag == "UNH"
1599 ),
1600 "expected InvalidSegmentForMessage(UNH), got: {:?}",
1601 results[0]
1602 );
1603 }
1604
1605 fn parse_one(input: &str) -> crate::OwnedSegment {
1608 crate::from_reader(std::io::Cursor::new(input.as_bytes()))
1609 .expect("parse failed")
1610 .into_iter()
1611 .next()
1612 .expect("at least one segment")
1613 }
1614
1615 #[test]
1616 fn segment_accessor_get_element_returns_value() {
1617 let owned = parse_one("BGM+220+PO-001+9'");
1618 let seg = owned.as_borrowed();
1619 assert_eq!(SegmentAccessor::get_element(&seg, 0), Some("220"));
1620 assert_eq!(SegmentAccessor::get_element(&seg, 1), Some("PO-001"));
1621 assert_eq!(SegmentAccessor::get_element(&seg, 2), Some("9"));
1622 assert_eq!(SegmentAccessor::get_element(&seg, 9), None, "out-of-bounds must return None");
1623 }
1624
1625 #[test]
1626 fn segment_accessor_get_element_filters_empty() {
1627 let owned = parse_one("TST+++VALUE'");
1628 let seg = owned.as_borrowed();
1629 assert_eq!(SegmentAccessor::get_element(&seg, 0), None, "empty element must return None");
1631 assert_eq!(SegmentAccessor::get_element(&seg, 1), None, "empty element must return None");
1632 assert_eq!(SegmentAccessor::get_element(&seg, 2), Some("VALUE"));
1633 }
1634
1635 #[test]
1636 fn segment_accessor_get_component_returns_value() {
1637 let owned = parse_one("UNH+1+ORDERS:D:96A:UN'");
1638 let seg = owned.as_borrowed();
1639 assert_eq!(seg.get_component(1, 0), Some("ORDERS"));
1640 assert_eq!(seg.get_component(1, 1), Some("D"));
1641 assert_eq!(seg.get_component(1, 2), Some("96A"));
1642 assert_eq!(seg.get_component(1, 3), Some("UN"));
1643 assert_eq!(seg.get_component(1, 9), None, "out-of-bounds must return None");
1644 }
1645
1646 #[test]
1647 fn segment_accessor_text_element_errors_on_missing() {
1648 let owned = parse_one("BGM+'");
1649 let seg = owned.as_borrowed();
1650 let err = seg.text_element(0);
1652 assert!(
1653 matches!(err, Err(EdifactError::MissingRequiredElement { ref tag, element_index: 0 }) if tag == "BGM"),
1654 "expected MissingRequiredElement, got: {err:?}"
1655 );
1656 }
1657
1658 #[test]
1659 fn segment_accessor_required_composite_errors_on_missing() {
1660 let owned = parse_one("DTM+137'");
1661 let seg = owned.as_borrowed();
1662 let err = seg.required_composite(0, 1);
1664 assert!(
1665 matches!(err, Err(EdifactError::MissingRequiredComponent { ref tag, element_index: 0, component_index: 1 }) if tag == "DTM"),
1666 "expected MissingRequiredComponent, got: {err:?}"
1667 );
1668 }
1669
1670 #[test]
1671 fn segment_accessor_code_element_parses_integer() {
1672 let owned = parse_one("QTY+21:100'");
1673 let seg = owned.as_borrowed();
1674 let qty: u32 = seg.code_element(0).expect("should parse qualifier as u32");
1675 assert_eq!(qty, 21);
1676 }
1677
1678 #[test]
1679 fn segment_accessor_optional_element_absent_returns_none() {
1680 let owned = parse_one("BGM+220'");
1681 let seg = owned.as_borrowed();
1682 assert_eq!(seg.optional_element(5), None);
1683 }
1684}