raknet-rust 0.2.0

Asynchronous, high-performance RakNet transport library for Rust.
Documentation
use bytes::{Buf, BufMut};

use crate::error::{DecodeError, EncodeError};

use super::codec::RaknetCodec;
use super::constants::MAX_ACK_SEQUENCES;
use super::sequence24::Sequence24;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SequenceRange {
    pub start: Sequence24,
    pub end: Sequence24,
}

impl SequenceRange {
    pub fn wraps(self) -> bool {
        self.start != self.end && self.start.value() > self.end.value()
    }

    pub fn split_wrapping(self) -> Option<(SequenceRange, SequenceRange)> {
        if !self.wraps() {
            return None;
        }

        let tail = SequenceRange {
            start: self.start,
            end: Sequence24::new(0x00FF_FFFF),
        };

        let head = SequenceRange {
            start: Sequence24::new(0),
            end: self.end,
        };

        Some((tail, head))
    }

    pub fn record_count(self) -> usize {
        if self.wraps() { 2 } else { 1 }
    }

    pub fn encoded_size(self) -> usize {
        if self.start == self.end {
            1 + 3
        } else {
            1 + 3 + 3
        }
    }
}

impl RaknetCodec for SequenceRange {
    fn encode_raknet(&self, dst: &mut impl BufMut) -> Result<(), EncodeError> {
        let singleton = self.start == self.end;
        singleton.encode_raknet(dst)?;
        self.start.encode_raknet(dst)?;
        if !singleton {
            self.end.encode_raknet(dst)?;
        }
        Ok(())
    }

    fn decode_raknet(src: &mut impl Buf) -> Result<Self, DecodeError> {
        let singleton = bool::decode_raknet(src)?;
        let start = Sequence24::decode_raknet(src)?;
        let end = if singleton {
            start
        } else {
            Sequence24::decode_raknet(src)?
        };

        Ok(Self { start, end })
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct AckNackPayload {
    pub ranges: Vec<SequenceRange>,
}

impl AckNackPayload {
    pub fn encoded_size(&self) -> usize {
        let mut size = 2usize;
        for r in &self.ranges {
            if let Some((a, b)) = r.split_wrapping() {
                size += a.encoded_size() + b.encoded_size();
            } else {
                size += r.encoded_size();
            }
        }
        size
    }
}

impl RaknetCodec for AckNackPayload {
    fn encode_raknet(&self, dst: &mut impl BufMut) -> Result<(), EncodeError> {
        let record_count: usize = self.ranges.iter().map(|r| r.record_count()).sum();
        if record_count > MAX_ACK_SEQUENCES as usize {
            return Err(EncodeError::AckRecordOverflow(record_count));
        }

        (record_count as u16).encode_raknet(dst)?;
        for range in &self.ranges {
            if let Some((left, right)) = range.split_wrapping() {
                left.encode_raknet(dst)?;
                right.encode_raknet(dst)?;
            } else {
                range.encode_raknet(dst)?;
            }
        }
        Ok(())
    }

    fn decode_raknet(src: &mut impl Buf) -> Result<Self, DecodeError> {
        let count = u16::decode_raknet(src)?;
        if count > MAX_ACK_SEQUENCES {
            return Err(DecodeError::InvalidAckRangeCount(count));
        }

        let mut ranges = Vec::with_capacity(count as usize);
        for _ in 0..count {
            ranges.push(SequenceRange::decode_raknet(src)?);
        }

        Ok(Self { ranges })
    }
}