internet 0.0.5

Network library for rust
Documentation
//! Stateful buffer traversal and byte-level manipulation.
//!
//! Dealing with raw offsets and tracking bounds manually leads to unreadable
//! and error-prone code. This module provides the `Cursor`, a stateful wrapper
//! around any `Buf` or `BufMut` that automatically manages the internal position.
//!
//! The [`Cursor`] allows for safe sequential reading and writing, advancing the internal
//! offset, or performing in-place mutations without ever losing track of protocol
//! boundaries or manually calculating slice indexes.

use crate::Buf;
use crate::BufError;
use crate::BufMut;
use crate::BufResult;

///
#[derive(Debug, Clone, Copy)]
pub struct Cursor<B: Buf> {
    buffer: B,
    position: usize,
}

impl<B: Buf> Cursor<B> {
    ///
    #[inline(always)]
    pub fn new(buffer: B) -> Self {
        Self {
            buffer,
            position: 0,
        }
    }

    ///
    #[inline(always)]
    pub fn into_inner(self) -> B {
        self.buffer
    }

    ///
    #[inline(always)]
    pub fn position(&self) -> usize {
        self.position
    }
}

///
impl<B: Buf> Cursor<B> {
    ///
    pub fn remaining(&self) -> usize {
        self.buffer.length().saturating_sub(self.position)
    }

    ///
    pub fn is_eof(&self) -> bool {
        self.position >= self.buffer.length()
    }

    ///
    pub fn advance(&mut self, amount: usize) -> BufResult<()> {
        if self.remaining() < amount {
            return Err(BufError::UnexpectedEof);
        }
        self.position += amount;
        Ok(())
    }

    ///
    pub fn rewind(&mut self, amount: usize) -> BufResult<()> {
        if self.position < amount {
            return Err(BufError::OutOfBounds);
        }
        self.position -= amount;
        Ok(())
    }

    ///
    pub fn seek_to(&mut self, absolute_pos: usize) -> BufResult<()> {
        if absolute_pos > self.buffer.length() {
            return Err(BufError::OutOfBounds);
        }
        self.position = absolute_pos;
        Ok(())
    }

    ///
    pub fn seek_from_end(&mut self, offset_from_end: usize) -> BufResult<()> {
        if offset_from_end > self.buffer.length() {
            return Err(BufError::OutOfBounds);
        }
        self.position = self.buffer.length() - offset_from_end;
        Ok(())
    }

    ///
    pub fn peek_u8(&self) -> BufResult<u8> {
        self.buffer.get_u8(self.position)
    }

    ///
    pub fn peek_u16_be(&self) -> BufResult<u16> {
        self.buffer.get_u16_be(self.position)
    }

    ///
    pub fn peek_u32_be(&self) -> BufResult<u32> {
        self.buffer.get_u32_be(self.position)
    }

    ///
    pub fn peek_array<const N: usize>(&self) -> BufResult<[u8; N]> {
        self.buffer.get_array::<N>(self.position)
    }

    ///
    pub fn read_u8(&mut self) -> BufResult<u8> {
        let val = self.peek_u8()?;
        self.advance(1)?;
        Ok(val)
    }

    ///
    pub fn read_u16_be(&mut self) -> BufResult<u16> {
        let val = self.peek_u16_be()?;
        self.advance(2)?;
        Ok(val)
    }

    ///
    pub fn read_u32_be(&mut self) -> BufResult<u32> {
        let val = self.peek_u32_be()?;
        self.advance(4)?;
        Ok(val)
    }

    ///
    pub fn read_array<const N: usize>(&mut self) -> BufResult<[u8; N]> {
        let val = self.peek_array::<N>()?;
        self.advance(N)?;
        Ok(val)
    }

    ///
    pub fn read_into(&mut self, dest: &mut [u8]) -> BufResult<()> {
        self.buffer.read_into(self.position, dest)?;
        self.advance(dest.len())?;
        Ok(())
    }
}

///
impl<B: BufMut> Cursor<B> {
    ///
    pub fn poke_u8(&mut self, val: u8) -> BufResult<()> {
        self.buffer.set_u8(self.position, val)
    }

    ///
    pub fn poke_u16_be(&mut self, val: u16) -> BufResult<()> {
        self.buffer.set_u16_be(self.position, val)
    }

    ///
    pub fn poke_u32_be(&mut self, val: u32) -> BufResult<()> {
        self.buffer.set_u32_be(self.position, val)
    }

    ///
    pub fn poke_array<const N: usize>(&mut self, val: &[u8; N]) -> BufResult<()> {
        self.buffer.set_array(self.position, val)
    }

    ///
    pub fn poke_slice(&mut self, src: &[u8]) -> BufResult<()> {
        self.buffer.set_slice(self.position, src)
    }

    ///
    pub fn write_u8(&mut self, val: u8) -> BufResult<()> {
        self.poke_u8(val)?;
        self.advance(1)?;
        Ok(())
    }

    ///
    pub fn write_u16_be(&mut self, val: u16) -> BufResult<()> {
        self.poke_u16_be(val)?;
        self.advance(2)?;
        Ok(())
    }

    ///
    pub fn write_u32_be(&mut self, val: u32) -> BufResult<()> {
        self.poke_u32_be(val)?;
        self.advance(4)?;
        Ok(())
    }

    ///
    pub fn write_array<const N: usize>(&mut self, val: &[u8; N]) -> BufResult<()> {
        self.poke_array(val)?;
        self.advance(N)?;
        Ok(())
    }

    ///
    pub fn write_slice(&mut self, src: &[u8]) -> BufResult<()> {
        self.poke_slice(src)?;
        self.advance(src.len())?;
        Ok(())
    }
}