Skip to main content

net_wire/kcp/
segment.rs

1//! Exact immutable and mutable KCP segment views.
2
3use super::error::KcpSegmentParseError;
4use super::types::{
5    KcpCommand, KcpConversationId, KcpFragment, KcpSequenceNumber, KcpTimestamp, KcpUnacknowledged,
6};
7
8/// The fixed KCP segment header length in bytes.
9pub const KCP_SEGMENT_HEADER_LEN: usize = 24;
10
11/// An exact borrowed KCP segment with a structurally complete declared payload.
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub struct KcpSegment<'a> {
14    bytes: &'a [u8],
15}
16
17impl<'a> KcpSegment<'a> {
18    /// Parses exactly one KCP segment and returns the unconsumed input suffix.
19    ///
20    /// This validates only structural boundaries. Raw command bytes and all field values are
21    /// preserved without runtime KCP semantic validation.
22    pub fn parse(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), KcpSegmentParseError> {
23        if bytes.len() < KCP_SEGMENT_HEADER_LEN {
24            return Err(KcpSegmentParseError::HeaderTruncated {
25                required: KCP_SEGMENT_HEADER_LEN,
26                available: bytes.len(),
27            });
28        }
29
30        let payload_length = u32::from_le_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]);
31        let payload_length = usize::try_from(payload_length).map_err(|_| {
32            KcpSegmentParseError::PayloadLengthNotRepresentable {
33                value: payload_length,
34            }
35        })?;
36        let length = KCP_SEGMENT_HEADER_LEN.checked_add(payload_length).ok_or(
37            KcpSegmentParseError::LengthOverflow {
38                header_length: KCP_SEGMENT_HEADER_LEN,
39                payload_length,
40            },
41        )?;
42        if bytes.len() < length {
43            return Err(KcpSegmentParseError::PayloadTruncated {
44                required: length,
45                available: bytes.len(),
46            });
47        }
48
49        Ok((
50            Self {
51                bytes: &bytes[..length],
52            },
53            &bytes[length..],
54        ))
55    }
56
57    /// Returns the conversation identifier.
58    pub const fn conversation_id(self) -> KcpConversationId {
59        KcpConversationId::new(u32::from_le_bytes([
60            self.bytes[0],
61            self.bytes[1],
62            self.bytes[2],
63            self.bytes[3],
64        ]))
65    }
66
67    /// Returns the raw command byte.
68    pub const fn command(self) -> KcpCommand {
69        KcpCommand::new(self.bytes[4])
70    }
71
72    /// Returns the fragment number.
73    pub const fn fragment(self) -> KcpFragment {
74        KcpFragment::new(self.bytes[5])
75    }
76
77    /// Returns the advertised receive window.
78    pub const fn window_size(self) -> u16 {
79        u16::from_le_bytes([self.bytes[6], self.bytes[7]])
80    }
81
82    /// Returns the timestamp.
83    pub const fn timestamp(self) -> KcpTimestamp {
84        KcpTimestamp::new(u32::from_le_bytes([
85            self.bytes[8],
86            self.bytes[9],
87            self.bytes[10],
88            self.bytes[11],
89        ]))
90    }
91
92    /// Returns the sequence number.
93    pub const fn sequence_number(self) -> KcpSequenceNumber {
94        KcpSequenceNumber::new(u32::from_le_bytes([
95            self.bytes[12],
96            self.bytes[13],
97            self.bytes[14],
98            self.bytes[15],
99        ]))
100    }
101
102    /// Returns the unacknowledged sequence-number marker.
103    pub const fn unacknowledged(self) -> KcpUnacknowledged {
104        KcpUnacknowledged::new(u32::from_le_bytes([
105            self.bytes[16],
106            self.bytes[17],
107            self.bytes[18],
108            self.bytes[19],
109        ]))
110    }
111
112    /// Returns the encoded payload length.
113    pub const fn payload_length(self) -> u32 {
114        u32::from_le_bytes([
115            self.bytes[20],
116            self.bytes[21],
117            self.bytes[22],
118            self.bytes[23],
119        ])
120    }
121
122    /// Returns the exact payload bytes.
123    pub fn payload(self) -> &'a [u8] {
124        &self.bytes[KCP_SEGMENT_HEADER_LEN..]
125    }
126
127    /// Returns the exact complete segment bytes, excluding any input suffix.
128    pub const fn as_bytes(self) -> &'a [u8] {
129        self.bytes
130    }
131}
132
133/// An exact mutable KCP segment with a structurally complete declared payload.
134#[derive(Debug, Eq, PartialEq)]
135pub struct KcpSegmentMut<'a> {
136    bytes: &'a mut [u8],
137}
138
139impl<'a> KcpSegmentMut<'a> {
140    /// Parses exactly one KCP segment and returns the unconsumed mutable input suffix.
141    ///
142    /// This validates only structural boundaries. Raw command bytes and all field values are
143    /// preserved without runtime KCP semantic validation.
144    pub fn parse(bytes: &'a mut [u8]) -> Result<(Self, &'a mut [u8]), KcpSegmentParseError> {
145        let (segment, _) = KcpSegment::parse(bytes)?;
146        let (segment_bytes, suffix) = bytes.split_at_mut(segment.as_bytes().len());
147        Ok((Self::from_validated(segment_bytes), suffix))
148    }
149
150    pub(crate) fn from_validated(bytes: &'a mut [u8]) -> Self {
151        Self { bytes }
152    }
153
154    /// Returns the conversation identifier.
155    pub fn conversation_id(&self) -> KcpConversationId {
156        KcpConversationId::new(u32::from_le_bytes([
157            self.bytes[0],
158            self.bytes[1],
159            self.bytes[2],
160            self.bytes[3],
161        ]))
162    }
163
164    /// Returns the raw command byte.
165    pub fn command(&self) -> KcpCommand {
166        KcpCommand::new(self.bytes[4])
167    }
168
169    /// Returns the fragment number.
170    pub fn fragment(&self) -> KcpFragment {
171        KcpFragment::new(self.bytes[5])
172    }
173
174    /// Returns the advertised receive window.
175    pub fn window_size(&self) -> u16 {
176        u16::from_le_bytes([self.bytes[6], self.bytes[7]])
177    }
178
179    /// Returns the timestamp.
180    pub fn timestamp(&self) -> KcpTimestamp {
181        KcpTimestamp::new(u32::from_le_bytes([
182            self.bytes[8],
183            self.bytes[9],
184            self.bytes[10],
185            self.bytes[11],
186        ]))
187    }
188
189    /// Returns the sequence number.
190    pub fn sequence_number(&self) -> KcpSequenceNumber {
191        KcpSequenceNumber::new(u32::from_le_bytes([
192            self.bytes[12],
193            self.bytes[13],
194            self.bytes[14],
195            self.bytes[15],
196        ]))
197    }
198
199    /// Returns the unacknowledged sequence-number marker.
200    pub fn unacknowledged(&self) -> KcpUnacknowledged {
201        KcpUnacknowledged::new(u32::from_le_bytes([
202            self.bytes[16],
203            self.bytes[17],
204            self.bytes[18],
205            self.bytes[19],
206        ]))
207    }
208
209    /// Returns the encoded payload length.
210    pub fn payload_length(&self) -> u32 {
211        u32::from_le_bytes([
212            self.bytes[20],
213            self.bytes[21],
214            self.bytes[22],
215            self.bytes[23],
216        ])
217    }
218
219    /// Returns the exact payload bytes.
220    pub fn payload(&self) -> &[u8] {
221        &self.bytes[KCP_SEGMENT_HEADER_LEN..]
222    }
223
224    /// Returns the exact payload bytes mutably without changing its encoded length.
225    pub fn payload_mut(&mut self) -> &mut [u8] {
226        &mut self.bytes[KCP_SEGMENT_HEADER_LEN..]
227    }
228
229    /// Returns the exact complete segment bytes, excluding any input suffix.
230    pub fn as_bytes(&self) -> &[u8] {
231        self.bytes
232    }
233
234    /// Replaces the conversation identifier.
235    pub fn set_conversation_id(&mut self, value: KcpConversationId) {
236        self.bytes[0..4].copy_from_slice(&value.raw().to_le_bytes());
237    }
238
239    /// Replaces the raw command byte.
240    pub fn set_command(&mut self, value: KcpCommand) {
241        self.bytes[4] = value.raw();
242    }
243
244    /// Replaces the fragment number.
245    pub fn set_fragment(&mut self, value: KcpFragment) {
246        self.bytes[5] = value.raw();
247    }
248
249    /// Replaces the advertised receive window.
250    pub fn set_window_size(&mut self, value: u16) {
251        self.bytes[6..8].copy_from_slice(&value.to_le_bytes());
252    }
253
254    /// Replaces the timestamp.
255    pub fn set_timestamp(&mut self, value: KcpTimestamp) {
256        self.bytes[8..12].copy_from_slice(&value.raw().to_le_bytes());
257    }
258
259    /// Replaces the sequence number.
260    pub fn set_sequence_number(&mut self, value: KcpSequenceNumber) {
261        self.bytes[12..16].copy_from_slice(&value.raw().to_le_bytes());
262    }
263
264    /// Replaces the unacknowledged sequence-number marker.
265    pub fn set_unacknowledged(&mut self, value: KcpUnacknowledged) {
266        self.bytes[16..20].copy_from_slice(&value.raw().to_le_bytes());
267    }
268}