Skip to main content

net_wire/kcp/
builder.rs

1//! KCP caller-buffer segment construction.
2
3use super::error::KcpSegmentBuildError;
4use super::segment::{KCP_SEGMENT_HEADER_LEN, KcpSegmentMut};
5use super::types::{
6    KcpCommand, KcpConversationId, KcpFragment, KcpSequenceNumber, KcpTimestamp, KcpUnacknowledged,
7};
8
9/// Builds one complete KCP segment in caller-owned storage.
10pub struct KcpSegmentBuilder<'a, 'b> {
11    destination: &'a mut [u8],
12    conversation_id: KcpConversationId,
13    command: KcpCommand,
14    payload: &'b [u8],
15    fragment: KcpFragment,
16    window_size: u16,
17    timestamp: KcpTimestamp,
18    sequence_number: KcpSequenceNumber,
19    unacknowledged: KcpUnacknowledged,
20}
21
22impl<'a, 'b> KcpSegmentBuilder<'a, 'b> {
23    /// Starts a builder with the required fields and a copied payload.
24    pub fn new(
25        destination: &'a mut [u8],
26        conversation_id: KcpConversationId,
27        command: KcpCommand,
28        payload: &'b [u8],
29    ) -> Self {
30        Self {
31            destination,
32            conversation_id,
33            command,
34            payload,
35            fragment: KcpFragment::new(0),
36            window_size: 0,
37            timestamp: KcpTimestamp::new(0),
38            sequence_number: KcpSequenceNumber::new(0),
39            unacknowledged: KcpUnacknowledged::new(0),
40        }
41    }
42
43    /// Supplies the fragment number; it defaults to zero.
44    pub fn fragment(mut self, value: KcpFragment) -> Self {
45        self.fragment = value;
46        self
47    }
48
49    /// Supplies the advertised receive window; it defaults to zero.
50    pub fn window_size(mut self, value: u16) -> Self {
51        self.window_size = value;
52        self
53    }
54
55    /// Supplies the timestamp; it defaults to zero.
56    pub fn timestamp(mut self, value: KcpTimestamp) -> Self {
57        self.timestamp = value;
58        self
59    }
60
61    /// Supplies the sequence number; it defaults to zero.
62    pub fn sequence_number(mut self, value: KcpSequenceNumber) -> Self {
63        self.sequence_number = value;
64        self
65    }
66
67    /// Supplies the unacknowledged marker; it defaults to zero.
68    pub fn unacknowledged(mut self, value: KcpUnacknowledged) -> Self {
69        self.unacknowledged = value;
70        self
71    }
72
73    /// Validates all boundaries, then writes one complete KCP segment.
74    pub fn build(self) -> Result<KcpSegmentMut<'a>, KcpSegmentBuildError> {
75        let payload_length = self.payload.len();
76        let encoded_payload_length = u32::try_from(payload_length).map_err(|_| {
77            KcpSegmentBuildError::PayloadLengthTooLarge {
78                length: payload_length,
79            }
80        })?;
81        let segment_length = KCP_SEGMENT_HEADER_LEN.checked_add(payload_length).ok_or(
82            KcpSegmentBuildError::LengthOverflow {
83                header_length: KCP_SEGMENT_HEADER_LEN,
84                payload_length,
85            },
86        )?;
87        if self.destination.len() < segment_length {
88            return Err(KcpSegmentBuildError::BufferTooShort {
89                required: segment_length,
90                available: self.destination.len(),
91            });
92        }
93
94        let bytes = &mut self.destination[..segment_length];
95        bytes[0..4].copy_from_slice(&self.conversation_id.raw().to_le_bytes());
96        bytes[4] = self.command.raw();
97        bytes[5] = self.fragment.raw();
98        bytes[6..8].copy_from_slice(&self.window_size.to_le_bytes());
99        bytes[8..12].copy_from_slice(&self.timestamp.raw().to_le_bytes());
100        bytes[12..16].copy_from_slice(&self.sequence_number.raw().to_le_bytes());
101        bytes[16..20].copy_from_slice(&self.unacknowledged.raw().to_le_bytes());
102        bytes[20..24].copy_from_slice(&encoded_payload_length.to_le_bytes());
103        bytes[KCP_SEGMENT_HEADER_LEN..].copy_from_slice(self.payload);
104        Ok(KcpSegmentMut::from_validated(bytes))
105    }
106}