Skip to main content

net_wire/kcp/
segments.rs

1//! Strict complete KCP segment-sequence validation and iteration.
2
3use core::iter::FusedIterator;
4
5use super::error::KcpSegmentsParseError;
6use super::segment::KcpSegment;
7
8/// A nonempty, completely validated concatenated KCP segment sequence.
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct KcpSegments<'a> {
11    bytes: &'a [u8],
12}
13
14impl<'a> KcpSegments<'a> {
15    /// Validates and borrows a complete nonempty concatenated KCP segment sequence.
16    ///
17    /// Every byte must belong to a structurally complete segment; trailing bytes shorter than a
18    /// KCP header are rejected rather than treated as padding.
19    pub fn parse(bytes: &'a [u8]) -> Result<Self, KcpSegmentsParseError> {
20        if bytes.is_empty() {
21            return Err(KcpSegmentsParseError::EmptySequence);
22        }
23
24        for segment in KcpSegmentIter::new(bytes) {
25            segment?;
26        }
27        Ok(Self { bytes })
28    }
29
30    /// Returns the exact complete sequence bytes.
31    pub const fn as_bytes(self) -> &'a [u8] {
32        self.bytes
33    }
34
35    /// Returns a fresh iterator over this sequence's validated segments.
36    pub const fn iter(self) -> KcpSegmentIter<'a> {
37        KcpSegmentIter::new(self.bytes)
38    }
39}
40
41/// A fallible fused iterator over concatenated KCP segments.
42///
43/// The iterator yields every structurally valid leading segment. On the first malformed segment,
44/// it yields one error with that segment's absolute offset and permanently exhausts itself.
45#[derive(Clone, Debug)]
46pub struct KcpSegmentIter<'a> {
47    remaining: &'a [u8],
48    offset: usize,
49    exhausted: bool,
50}
51
52impl<'a> KcpSegmentIter<'a> {
53    /// Creates an iterator over a raw concatenated KCP segment sequence without prevalidation.
54    pub const fn new(bytes: &'a [u8]) -> Self {
55        Self {
56            remaining: bytes,
57            offset: 0,
58            exhausted: false,
59        }
60    }
61}
62
63impl<'a> Iterator for KcpSegmentIter<'a> {
64    type Item = Result<KcpSegment<'a>, KcpSegmentsParseError>;
65
66    fn next(&mut self) -> Option<Self::Item> {
67        if self.exhausted || self.remaining.is_empty() {
68            self.exhausted = true;
69            return None;
70        }
71
72        match KcpSegment::parse(self.remaining) {
73            Ok((segment, suffix)) => {
74                let length = segment.as_bytes().len();
75                self.offset += length;
76                self.remaining = suffix;
77                Some(Ok(segment))
78            }
79            Err(error) => self.fail(KcpSegmentsParseError::Segment {
80                offset: self.offset,
81                error,
82            }),
83        }
84    }
85}
86
87impl FusedIterator for KcpSegmentIter<'_> {}
88
89impl<'a> KcpSegmentIter<'a> {
90    fn fail(
91        &mut self,
92        error: KcpSegmentsParseError,
93    ) -> Option<Result<KcpSegment<'a>, KcpSegmentsParseError>> {
94        self.remaining = &[];
95        self.exhausted = true;
96        Some(Err(error))
97    }
98}