Skip to main content

ReadBuf

Struct ReadBuf 

Source
pub struct ReadBuf { /* private fields */ }
Expand description

Flat byte slab for inbound protocol parsing.

The I/O layer reads bytes into the slab via spare() + filled(). The protocol parser walks it via data() + advance(). When all data is consumed, cursors reset to the pre-padding offset — no memmove.

Fixed capacity. No growth.

§Layout

[ pre_padding | usable capacity                        | post_padding ]
              ^                                        ^
              head/tail start here                     end of usable

Pre-padding: reserved bytes before the data region. Protocol layers can use this for header reassembly (e.g., uWS writes spilled header bytes backward into pre-padding). Accessible via pre_padding_mut().

Post-padding: reserved bytes after the data region. SIMD operations may overrun by up to alignment width. ReadBuf guarantees this space exists but doesn’t manage it.

§Examples

use nexus_net::buf::ReadBuf;

let mut buf = ReadBuf::with_capacity(4096);

// I/O: read bytes into spare region
let spare = buf.spare();
spare[..5].copy_from_slice(b"Hello");
buf.filled(5);

// Parse: consume from data region
assert_eq!(buf.data(), b"Hello");
buf.advance(5);
assert!(buf.is_empty()); // cursors auto-reset

Implementations§

Source§

impl ReadBuf

Source

pub fn new(capacity: usize, pre_padding: usize, post_padding: usize) -> ReadBuf

Create a ReadBuf with explicit padding.

Total allocation: pre_padding + capacity + post_padding. The buffer is fixed-size — it never reallocates.

Source

pub fn with_capacity(capacity: usize) -> ReadBuf

Convenience: capacity only, zero padding.

Source

pub fn data(&self) -> &[u8]

Unconsumed bytes. Always a single contiguous slice.

Source

pub fn data_mut(&mut self) -> &mut [u8]

Mutable access to unconsumed bytes. For in-place operations like XOR unmasking.

Source

pub fn advance(&mut self, n: usize)

Consume n bytes from the front.

If the buffer becomes empty after advance, resets head and tail to pre_padding offset (free — no memmove, just cursor reset).

§Panics

Panics if n > self.len().

Source

pub fn spare(&mut self) -> &mut [u8]

Writable tail region for direct socket reads.

let n = socket.read(buf.spare())?;
buf.filled(n);

Returns buf[tail .. pre_padding + capacity]. May be empty if tail has reached the capacity boundary.

Source

pub fn filled(&mut self, n: usize)

Commit n bytes written into spare().

§Panics

Panics if n would push tail past capacity boundary.

Source

pub fn pre_padding_mut(&mut self) -> &mut [u8]

Mutable access to the pre-padding region (bytes before head).

Returns buf[0..head]. Protocol layers can use this for header reassembly — e.g., writing spilled header bytes backward so the parser sees a contiguous header without memmove.

The returned slice includes both the original pre-padding AND any consumed-but-not-reset space before head.

Source

pub fn len(&self) -> usize

Bytes of unconsumed data.

Source

pub fn is_empty(&self) -> bool

Whether the buffer is empty.

Source

pub fn capacity(&self) -> usize

Usable capacity (excluding padding).

Source

pub fn remaining(&self) -> usize

Writable space at the tail (same as spare().len()).

Source

pub fn clear(&mut self)

Discard all data. Cursors reset to pre_padding offset.

Source

pub fn consumed(&self) -> usize

Bytes consumed from the front (how far head has advanced from start).

Useful for determining when to proactively compact().

Source

pub fn compact(&mut self)

Reclaim consumed space by moving unconsumed data to the front.

Call when spare() is empty but there is consumed space before head that can be reclaimed. The unconsumed data (typically a partial frame) is moved to the pre_padding offset.

Cost: O(unconsumed bytes). For a partial frame this is typically a few hundred bytes — under 100ns.

No-op if the buffer is already at the front or empty.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V