x12_stream_parser/
segment.rs

1use std::fmt;
2
3#[derive(Clone, Copy, PartialEq, Eq)]
4pub struct SegmentSlice<'a> {
5    id: &'a [u8],
6    data: &'a [u8],
7    element_separator: u8,
8    sub_element_separator: u8,
9}
10
11impl<'a> SegmentSlice<'a> {
12    pub(crate) fn new(
13        full_segment: &'a [u8],
14        element_separator: u8,
15        sub_element_separator: u8,
16    ) -> Option<Self> {
17        if full_segment.is_empty() {
18            return None;
19        }
20
21        let id_end = full_segment
22            .iter()
23            .position(|&b| b == element_separator)
24            .unwrap_or(full_segment.len());
25
26        let id = &full_segment[..id_end];
27
28        if id.is_empty() {
29             return None; // Cannot have empty ID
30        }
31
32        let data = if id_end < full_segment.len() {
33            // Skip the separator itself for data part
34            &full_segment[id_end + 1..]
35        } else {
36            // No separator found, data is empty
37            &full_segment[id_end..]
38        };
39
40
41        Some(SegmentSlice {
42            id,
43            data,
44            element_separator,
45            sub_element_separator,
46        })
47    }
48
49    pub fn id(&self) -> &'a [u8] {
50        self.id
51    }
52
53    pub fn elements(&self) -> ElementIterator<'a> {
54        ElementIterator {
55            remaining_data: self.data,
56            separator: self.element_separator,
57        }
58    }
59
60    pub fn element_separator(&self) -> u8 {
61        self.element_separator
62    }
63
64    pub fn sub_element_separator(&self) -> u8 {
65        self.sub_element_separator
66    }
67}
68
69impl<'a> fmt::Debug for SegmentSlice<'a> {
70     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71         f.debug_struct("SegmentSlice")
72          .field("id", &String::from_utf8_lossy(self.id))
73          .field("data", &String::from_utf8_lossy(self.data))
74          .field("element_separator", &(self.element_separator as char))
75          .field("sub_element_separator", &(self.sub_element_separator as char))
76          .finish()
77     }
78 }
79
80
81#[derive(Clone)]
82pub struct ElementIterator<'a> {
83    remaining_data: &'a [u8],
84    separator: u8,
85}
86
87impl<'a> Iterator for ElementIterator<'a> {
88    type Item = &'a [u8];
89
90    fn next(&mut self) -> Option<Self::Item> {
91        if self.remaining_data.is_empty() {
92            // Check if the original data was empty vs ended on a separator
93            // If it ended on a separator previously, the last element is empty, yield it once.
94            // If it was truly empty, return None. This logic is tricky, simpler to use std::mem::take
95            // Alternative: Use a flag?
96            // Let's handle the case where input ends with a separator: split returns an empty slice at the end.
97            return None; // No more data left
98        }
99
100        let mut split_iter = self.remaining_data.splitn(2, |&b| b == self.separator);
101
102        let element = split_iter.next().unwrap_or_default(); // Should always return at least one part
103        self.remaining_data = split_iter.next().unwrap_or_else(|| &[]); // The rest, or empty slice if no separator found
104
105        Some(element)
106    }
107}
108
109// Helper function for downstream users to split elements. Not part of core iteration.
110pub fn split_sub_elements<'a>(element_data: &'a[u8], separator: u8) -> impl Iterator<Item = &'a [u8]> + Clone + 'a {
111     element_data.split(move |&b| b == separator)
112}