use super::error::KcpSegmentParseError;
use super::types::{
KcpCommand, KcpConversationId, KcpFragment, KcpSequenceNumber, KcpTimestamp, KcpUnacknowledged,
};
pub const KCP_SEGMENT_HEADER_LEN: usize = 24;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct KcpSegment<'a> {
bytes: &'a [u8],
}
impl<'a> KcpSegment<'a> {
pub fn parse(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), KcpSegmentParseError> {
if bytes.len() < KCP_SEGMENT_HEADER_LEN {
return Err(KcpSegmentParseError::HeaderTruncated {
required: KCP_SEGMENT_HEADER_LEN,
available: bytes.len(),
});
}
let payload_length = u32::from_le_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]);
let payload_length = usize::try_from(payload_length).map_err(|_| {
KcpSegmentParseError::PayloadLengthNotRepresentable {
value: payload_length,
}
})?;
let length = KCP_SEGMENT_HEADER_LEN.checked_add(payload_length).ok_or(
KcpSegmentParseError::LengthOverflow {
header_length: KCP_SEGMENT_HEADER_LEN,
payload_length,
},
)?;
if bytes.len() < length {
return Err(KcpSegmentParseError::PayloadTruncated {
required: length,
available: bytes.len(),
});
}
Ok((
Self {
bytes: &bytes[..length],
},
&bytes[length..],
))
}
pub const fn conversation_id(self) -> KcpConversationId {
KcpConversationId::new(u32::from_le_bytes([
self.bytes[0],
self.bytes[1],
self.bytes[2],
self.bytes[3],
]))
}
pub const fn command(self) -> KcpCommand {
KcpCommand::new(self.bytes[4])
}
pub const fn fragment(self) -> KcpFragment {
KcpFragment::new(self.bytes[5])
}
pub const fn window_size(self) -> u16 {
u16::from_le_bytes([self.bytes[6], self.bytes[7]])
}
pub const fn timestamp(self) -> KcpTimestamp {
KcpTimestamp::new(u32::from_le_bytes([
self.bytes[8],
self.bytes[9],
self.bytes[10],
self.bytes[11],
]))
}
pub const fn sequence_number(self) -> KcpSequenceNumber {
KcpSequenceNumber::new(u32::from_le_bytes([
self.bytes[12],
self.bytes[13],
self.bytes[14],
self.bytes[15],
]))
}
pub const fn unacknowledged(self) -> KcpUnacknowledged {
KcpUnacknowledged::new(u32::from_le_bytes([
self.bytes[16],
self.bytes[17],
self.bytes[18],
self.bytes[19],
]))
}
pub const fn payload_length(self) -> u32 {
u32::from_le_bytes([
self.bytes[20],
self.bytes[21],
self.bytes[22],
self.bytes[23],
])
}
pub fn payload(self) -> &'a [u8] {
&self.bytes[KCP_SEGMENT_HEADER_LEN..]
}
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct KcpSegmentMut<'a> {
bytes: &'a mut [u8],
}
impl<'a> KcpSegmentMut<'a> {
pub fn parse(bytes: &'a mut [u8]) -> Result<(Self, &'a mut [u8]), KcpSegmentParseError> {
let (segment, _) = KcpSegment::parse(bytes)?;
let (segment_bytes, suffix) = bytes.split_at_mut(segment.as_bytes().len());
Ok((Self::from_validated(segment_bytes), suffix))
}
pub(crate) fn from_validated(bytes: &'a mut [u8]) -> Self {
Self { bytes }
}
pub fn conversation_id(&self) -> KcpConversationId {
KcpConversationId::new(u32::from_le_bytes([
self.bytes[0],
self.bytes[1],
self.bytes[2],
self.bytes[3],
]))
}
pub fn command(&self) -> KcpCommand {
KcpCommand::new(self.bytes[4])
}
pub fn fragment(&self) -> KcpFragment {
KcpFragment::new(self.bytes[5])
}
pub fn window_size(&self) -> u16 {
u16::from_le_bytes([self.bytes[6], self.bytes[7]])
}
pub fn timestamp(&self) -> KcpTimestamp {
KcpTimestamp::new(u32::from_le_bytes([
self.bytes[8],
self.bytes[9],
self.bytes[10],
self.bytes[11],
]))
}
pub fn sequence_number(&self) -> KcpSequenceNumber {
KcpSequenceNumber::new(u32::from_le_bytes([
self.bytes[12],
self.bytes[13],
self.bytes[14],
self.bytes[15],
]))
}
pub fn unacknowledged(&self) -> KcpUnacknowledged {
KcpUnacknowledged::new(u32::from_le_bytes([
self.bytes[16],
self.bytes[17],
self.bytes[18],
self.bytes[19],
]))
}
pub fn payload_length(&self) -> u32 {
u32::from_le_bytes([
self.bytes[20],
self.bytes[21],
self.bytes[22],
self.bytes[23],
])
}
pub fn payload(&self) -> &[u8] {
&self.bytes[KCP_SEGMENT_HEADER_LEN..]
}
pub fn payload_mut(&mut self) -> &mut [u8] {
&mut self.bytes[KCP_SEGMENT_HEADER_LEN..]
}
pub fn as_bytes(&self) -> &[u8] {
self.bytes
}
pub fn set_conversation_id(&mut self, value: KcpConversationId) {
self.bytes[0..4].copy_from_slice(&value.raw().to_le_bytes());
}
pub fn set_command(&mut self, value: KcpCommand) {
self.bytes[4] = value.raw();
}
pub fn set_fragment(&mut self, value: KcpFragment) {
self.bytes[5] = value.raw();
}
pub fn set_window_size(&mut self, value: u16) {
self.bytes[6..8].copy_from_slice(&value.to_le_bytes());
}
pub fn set_timestamp(&mut self, value: KcpTimestamp) {
self.bytes[8..12].copy_from_slice(&value.raw().to_le_bytes());
}
pub fn set_sequence_number(&mut self, value: KcpSequenceNumber) {
self.bytes[12..16].copy_from_slice(&value.raw().to_le_bytes());
}
pub fn set_unacknowledged(&mut self, value: KcpUnacknowledged) {
self.bytes[16..20].copy_from_slice(&value.raw().to_le_bytes());
}
}