docs(length_prefix_encoding): fix docstring warnings

Signed-off-by: Paul Spooren <mail@aparcar.org>
This commit is contained in:
Paul Spooren
2024-11-06 17:37:35 +01:00
parent 0836a2eb28
commit 43cb0c09c5
3 changed files with 122 additions and 0 deletions

View File

@@ -8,28 +8,37 @@ use crate::{
result::ensure_or, result::ensure_or,
}; };
/// Size in bytes of a message header carrying length information
pub const HEADER_SIZE: usize = std::mem::size_of::<u64>(); pub const HEADER_SIZE: usize = std::mem::size_of::<u64>();
#[derive(Error, Debug)] #[derive(Error, Debug)]
/// Error enum to represent various boundary sanity check failures during buffer operations
pub enum SanityError { pub enum SanityError {
#[error("Offset is out of read buffer bounds")] #[error("Offset is out of read buffer bounds")]
/// Error indicating that the given offset exceeds the bounds of the read buffer
OutOfBufferBounds, OutOfBufferBounds,
#[error("Offset is out of message buffer bounds")] #[error("Offset is out of message buffer bounds")]
/// Error indicating that the given offset exceeds the bounds of the message buffer
OutOfMessageBounds, OutOfMessageBounds,
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
#[error("Message too large ({msg_size} bytes) for buffer ({buf_size} bytes)")] #[error("Message too large ({msg_size} bytes) for buffer ({buf_size} bytes)")]
/// Error indicating that message exceeds available buffer space
pub struct MessageTooLargeError { pub struct MessageTooLargeError {
msg_size: usize, msg_size: usize,
buf_size: usize, buf_size: usize,
} }
impl MessageTooLargeError { impl MessageTooLargeError {
/// Creates a new MessageTooLargeError with the given message and buffer sizes
pub fn new(msg_size: usize, buf_size: usize) -> Self { pub fn new(msg_size: usize, buf_size: usize) -> Self {
Self { msg_size, buf_size } Self { msg_size, buf_size }
} }
/// Ensures that the message size fits within the buffer size
///
/// Returns Ok(()) if the message fits, otherwise returns an error with size details
pub fn ensure(msg_size: usize, buf_size: usize) -> Result<(), Self> { pub fn ensure(msg_size: usize, buf_size: usize) -> Result<(), Self> {
let err = MessageTooLargeError { msg_size, buf_size }; let err = MessageTooLargeError { msg_size, buf_size };
ensure_or(msg_size <= buf_size, err) ensure_or(msg_size <= buf_size, err)
@@ -37,12 +46,16 @@ impl MessageTooLargeError {
} }
#[derive(Debug)] #[derive(Debug)]
/// Return type for ReadFromIo operations that contains the number of bytes read and an optional message slice
pub struct ReadFromIoReturn<'a> { pub struct ReadFromIoReturn<'a> {
/// Number of bytes read from the input
pub bytes_read: usize, pub bytes_read: usize,
/// Optional slice containing the complete message, if one was read
pub message: Option<&'a mut [u8]>, pub message: Option<&'a mut [u8]>,
} }
impl<'a> ReadFromIoReturn<'a> { impl<'a> ReadFromIoReturn<'a> {
/// Creates a new ReadFromIoReturn with the given number of bytes read and optional message slice.
pub fn new(bytes_read: usize, message: Option<&'a mut [u8]>) -> Self { pub fn new(bytes_read: usize, message: Option<&'a mut [u8]>) -> Self {
Self { Self {
bytes_read, bytes_read,
@@ -52,9 +65,12 @@ impl<'a> ReadFromIoReturn<'a> {
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]
/// An enum representing errors that can occur during read operations from I/O
pub enum ReadFromIoError { pub enum ReadFromIoError {
/// Error occurred while reading from the underlying I/O stream
#[error("Error reading from the underlying stream")] #[error("Error reading from the underlying stream")]
IoError(#[from] io::Error), IoError(#[from] io::Error),
/// Error occurred because message size exceeded buffer capacity
#[error("Message size out of buffer bounds")] #[error("Message size out of buffer bounds")]
MessageTooLargeError(#[from] MessageTooLargeError), MessageTooLargeError(#[from] MessageTooLargeError),
} }
@@ -69,6 +85,10 @@ impl TryIoErrorKind for ReadFromIoError {
} }
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
/// A decoder for length-prefixed messages
///
/// This struct provides functionality to decode messages that are prefixed with their length.
/// It maintains internal state for header information, the message buffer, and current offset.
pub struct LengthPrefixDecoder<Buf: BorrowMut<[u8]>> { pub struct LengthPrefixDecoder<Buf: BorrowMut<[u8]>> {
header: [u8; HEADER_SIZE], header: [u8; HEADER_SIZE],
buf: Buf, buf: Buf,
@@ -76,25 +96,33 @@ pub struct LengthPrefixDecoder<Buf: BorrowMut<[u8]>> {
} }
impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> { impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
/// Creates a new LengthPrefixDecoder with the given buffer
pub fn new(buf: Buf) -> Self { pub fn new(buf: Buf) -> Self {
let header = Default::default(); let header = Default::default();
let off = 0; let off = 0;
Self { header, buf, off } Self { header, buf, off }
} }
/// Clears and zeroes all internal state
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.zeroize() self.zeroize()
} }
/// Creates a new LengthPrefixDecoder from its component parts
pub fn from_parts(header: [u8; HEADER_SIZE], buf: Buf, off: usize) -> Self { pub fn from_parts(header: [u8; HEADER_SIZE], buf: Buf, off: usize) -> Self {
Self { header, buf, off } Self { header, buf, off }
} }
/// Consumes the decoder and returns its component parts
pub fn into_parts(self) -> ([u8; HEADER_SIZE], Buf, usize) { pub fn into_parts(self) -> ([u8; HEADER_SIZE], Buf, usize) {
let Self { header, buf, off } = self; let Self { header, buf, off } = self;
(header, buf, off) (header, buf, off)
} }
/// Reads a complete message from the given reader into the decoder.
///
/// Retries on interrupts and returns the decoded message buffer on success.
/// Returns an error if the read fails or encounters an unexpected EOF.
pub fn read_all_from_stdio<R: io::Read>( pub fn read_all_from_stdio<R: io::Read>(
&mut self, &mut self,
mut r: R, mut r: R,
@@ -125,6 +153,7 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
} }
} }
/// Reads from the given reader into the decoder's internal buffers
pub fn read_from_stdio<R: io::Read>( pub fn read_from_stdio<R: io::Read>(
&mut self, &mut self,
mut r: R, mut r: R,
@@ -150,6 +179,7 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
}) })
} }
/// Gets the next buffer slice that can be written to
pub fn next_slice_to_write_to(&mut self) -> Result<Option<&mut [u8]>, MessageTooLargeError> { pub fn next_slice_to_write_to(&mut self) -> Result<Option<&mut [u8]>, MessageTooLargeError> {
fn some_if_nonempty(buf: &mut [u8]) -> Option<&mut [u8]> { fn some_if_nonempty(buf: &mut [u8]) -> Option<&mut [u8]> {
match buf.is_empty() { match buf.is_empty() {
@@ -172,6 +202,7 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
Ok(None) Ok(None)
} }
/// Advances the internal offset by the specified number of bytes
pub fn advance(&mut self, count: usize) -> Result<(), SanityError> { pub fn advance(&mut self, count: usize) -> Result<(), SanityError> {
let off = self.off + count; let off = self.off + count;
let msg_off = off.saturating_sub(HEADER_SIZE); let msg_off = off.saturating_sub(HEADER_SIZE);
@@ -189,6 +220,7 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
Ok(()) Ok(())
} }
/// Ensures that the internal message buffer is large enough for the message size in the header
pub fn ensure_sufficient_msg_buffer(&self) -> Result<(), MessageTooLargeError> { pub fn ensure_sufficient_msg_buffer(&self) -> Result<(), MessageTooLargeError> {
let buf_size = self.message_buffer().len(); let buf_size = self.message_buffer().len();
let msg_size = match self.get_header() { let msg_size = match self.get_header() {
@@ -198,43 +230,53 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
MessageTooLargeError::ensure(msg_size, buf_size) MessageTooLargeError::ensure(msg_size, buf_size)
} }
/// Returns a reference to the header buffer
pub fn header_buffer(&self) -> &[u8] { pub fn header_buffer(&self) -> &[u8] {
&self.header[..] &self.header[..]
} }
/// Returns a mutable reference to the header buffer
pub fn header_buffer_mut(&mut self) -> &mut [u8] { pub fn header_buffer_mut(&mut self) -> &mut [u8] {
&mut self.header[..] &mut self.header[..]
} }
/// Returns a reference to the message buffer
pub fn message_buffer(&self) -> &[u8] { pub fn message_buffer(&self) -> &[u8] {
self.buf.borrow() self.buf.borrow()
} }
/// Returns a mutable reference to the message buffer
pub fn message_buffer_mut(&mut self) -> &mut [u8] { pub fn message_buffer_mut(&mut self) -> &mut [u8] {
self.buf.borrow_mut() self.buf.borrow_mut()
} }
/// Returns the number of bytes read so far
pub fn bytes_read(&self) -> &usize { pub fn bytes_read(&self) -> &usize {
&self.off &self.off
} }
/// Consumes the decoder and returns just the message buffer
pub fn into_message_buffer(self) -> Buf { pub fn into_message_buffer(self) -> Buf {
let Self { buf, .. } = self; let Self { buf, .. } = self;
buf buf
} }
/// Returns the current offset into the header buffer
pub fn header_buffer_offset(&self) -> usize { pub fn header_buffer_offset(&self) -> usize {
min(self.off, HEADER_SIZE) min(self.off, HEADER_SIZE)
} }
/// Returns the current offset into the message buffer
pub fn message_buffer_offset(&self) -> usize { pub fn message_buffer_offset(&self) -> usize {
self.off.saturating_sub(HEADER_SIZE) self.off.saturating_sub(HEADER_SIZE)
} }
/// Returns whether a complete header has been read
pub fn has_header(&self) -> bool { pub fn has_header(&self) -> bool {
self.header_buffer_offset() == HEADER_SIZE self.header_buffer_offset() == HEADER_SIZE
} }
/// Returns whether a complete message has been read
pub fn has_message(&self) -> Result<bool, MessageTooLargeError> { pub fn has_message(&self) -> Result<bool, MessageTooLargeError> {
self.ensure_sufficient_msg_buffer()?; self.ensure_sufficient_msg_buffer()?;
let msg_size = match self.get_header() { let msg_size = match self.get_header() {
@@ -244,46 +286,55 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
Ok(self.message_buffer_avail().len() == msg_size) Ok(self.message_buffer_avail().len() == msg_size)
} }
/// Returns a slice of the available data in the header buffer
pub fn header_buffer_avail(&self) -> &[u8] { pub fn header_buffer_avail(&self) -> &[u8] {
let off = self.header_buffer_offset(); let off = self.header_buffer_offset();
&self.header_buffer()[..off] &self.header_buffer()[..off]
} }
/// Returns a mutable slice of the available data in the header buffer
pub fn header_buffer_avail_mut(&mut self) -> &mut [u8] { pub fn header_buffer_avail_mut(&mut self) -> &mut [u8] {
let off = self.header_buffer_offset(); let off = self.header_buffer_offset();
&mut self.header_buffer_mut()[..off] &mut self.header_buffer_mut()[..off]
} }
/// Returns a slice of the remaining space in the header buffer
pub fn header_buffer_left(&self) -> &[u8] { pub fn header_buffer_left(&self) -> &[u8] {
let off = self.header_buffer_offset(); let off = self.header_buffer_offset();
&self.header_buffer()[off..] &self.header_buffer()[off..]
} }
/// Returns a mutable slice of the remaining space in the header buffer
pub fn header_buffer_left_mut(&mut self) -> &mut [u8] { pub fn header_buffer_left_mut(&mut self) -> &mut [u8] {
let off = self.header_buffer_offset(); let off = self.header_buffer_offset();
&mut self.header_buffer_mut()[off..] &mut self.header_buffer_mut()[off..]
} }
/// Returns a slice of the available data in the message buffer
pub fn message_buffer_avail(&self) -> &[u8] { pub fn message_buffer_avail(&self) -> &[u8] {
let off = self.message_buffer_offset(); let off = self.message_buffer_offset();
&self.message_buffer()[..off] &self.message_buffer()[..off]
} }
/// Returns a mutable slice of the available data in the message buffer
pub fn message_buffer_avail_mut(&mut self) -> &mut [u8] { pub fn message_buffer_avail_mut(&mut self) -> &mut [u8] {
let off = self.message_buffer_offset(); let off = self.message_buffer_offset();
&mut self.message_buffer_mut()[..off] &mut self.message_buffer_mut()[..off]
} }
/// Returns a slice of the remaining space in the message buffer
pub fn message_buffer_left(&self) -> &[u8] { pub fn message_buffer_left(&self) -> &[u8] {
let off = self.message_buffer_offset(); let off = self.message_buffer_offset();
&self.message_buffer()[off..] &self.message_buffer()[off..]
} }
/// Returns a mutable slice of the remaining space in the message buffer
pub fn message_buffer_left_mut(&mut self) -> &mut [u8] { pub fn message_buffer_left_mut(&mut self) -> &mut [u8] {
let off = self.message_buffer_offset(); let off = self.message_buffer_offset();
&mut self.message_buffer_mut()[off..] &mut self.message_buffer_mut()[off..]
} }
/// Returns the message size from the header if available
pub fn get_header(&self) -> Option<usize> { pub fn get_header(&self) -> Option<usize> {
match self.header_buffer_offset() == HEADER_SIZE { match self.header_buffer_offset() == HEADER_SIZE {
false => None, false => None,
@@ -291,19 +342,23 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
} }
} }
/// Returns the size of the message if header is available
pub fn message_size(&self) -> Option<usize> { pub fn message_size(&self) -> Option<usize> {
self.get_header() self.get_header()
} }
/// Returns the total size of the encoded message including header
pub fn encoded_message_bytes(&self) -> Option<usize> { pub fn encoded_message_bytes(&self) -> Option<usize> {
self.message_size().map(|sz| sz + HEADER_SIZE) self.message_size().map(|sz| sz + HEADER_SIZE)
} }
/// Returns a slice of the message fragment if available
pub fn message_fragment(&self) -> Result<Option<&[u8]>, MessageTooLargeError> { pub fn message_fragment(&self) -> Result<Option<&[u8]>, MessageTooLargeError> {
self.ensure_sufficient_msg_buffer()?; self.ensure_sufficient_msg_buffer()?;
Ok(self.message_size().map(|sz| &self.message_buffer()[..sz])) Ok(self.message_size().map(|sz| &self.message_buffer()[..sz]))
} }
/// Returns a mutable slice of the message fragment if available
pub fn message_fragment_mut(&mut self) -> Result<Option<&mut [u8]>, MessageTooLargeError> { pub fn message_fragment_mut(&mut self) -> Result<Option<&mut [u8]>, MessageTooLargeError> {
self.ensure_sufficient_msg_buffer()?; self.ensure_sufficient_msg_buffer()?;
Ok(self Ok(self
@@ -311,12 +366,14 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
.map(|sz| &mut self.message_buffer_mut()[..sz])) .map(|sz| &mut self.message_buffer_mut()[..sz]))
} }
/// Returns a slice of the available data in the message fragment
pub fn message_fragment_avail(&self) -> Result<Option<&[u8]>, MessageTooLargeError> { pub fn message_fragment_avail(&self) -> Result<Option<&[u8]>, MessageTooLargeError> {
let off = self.message_buffer_avail().len(); let off = self.message_buffer_avail().len();
self.message_fragment() self.message_fragment()
.map(|frag| frag.map(|frag| &frag[..off])) .map(|frag| frag.map(|frag| &frag[..off]))
} }
/// Returns a mutable slice of the available data in the message fragment
pub fn message_fragment_avail_mut( pub fn message_fragment_avail_mut(
&mut self, &mut self,
) -> Result<Option<&mut [u8]>, MessageTooLargeError> { ) -> Result<Option<&mut [u8]>, MessageTooLargeError> {
@@ -325,24 +382,28 @@ impl<Buf: BorrowMut<[u8]>> LengthPrefixDecoder<Buf> {
.map(|frag| frag.map(|frag| &mut frag[..off])) .map(|frag| frag.map(|frag| &mut frag[..off]))
} }
/// Returns a slice of the remaining space in the message fragment
pub fn message_fragment_left(&self) -> Result<Option<&[u8]>, MessageTooLargeError> { pub fn message_fragment_left(&self) -> Result<Option<&[u8]>, MessageTooLargeError> {
let off = self.message_buffer_avail().len(); let off = self.message_buffer_avail().len();
self.message_fragment() self.message_fragment()
.map(|frag| frag.map(|frag| &frag[off..])) .map(|frag| frag.map(|frag| &frag[off..]))
} }
/// Returns a mutable slice of the remaining space in the message fragment
pub fn message_fragment_left_mut(&mut self) -> Result<Option<&mut [u8]>, MessageTooLargeError> { pub fn message_fragment_left_mut(&mut self) -> Result<Option<&mut [u8]>, MessageTooLargeError> {
let off = self.message_buffer_avail().len(); let off = self.message_buffer_avail().len();
self.message_fragment_mut() self.message_fragment_mut()
.map(|frag| frag.map(|frag| &mut frag[off..])) .map(|frag| frag.map(|frag| &mut frag[off..]))
} }
/// Returns a slice of the complete message if available
pub fn message(&self) -> Result<Option<&[u8]>, MessageTooLargeError> { pub fn message(&self) -> Result<Option<&[u8]>, MessageTooLargeError> {
let sz = self.message_size(); let sz = self.message_size();
self.message_fragment_avail() self.message_fragment_avail()
.map(|frag_opt| frag_opt.and_then(|frag| (frag.len() == sz?).then_some(frag))) .map(|frag_opt| frag_opt.and_then(|frag| (frag.len() == sz?).then_some(frag)))
} }
/// Returns a mutable slice of the complete message if available
pub fn message_mut(&mut self) -> Result<Option<&mut [u8]>, MessageTooLargeError> { pub fn message_mut(&mut self) -> Result<Option<&mut [u8]>, MessageTooLargeError> {
let sz = self.message_size(); let sz = self.message_size();
self.message_fragment_avail_mut() self.message_fragment_avail_mut()

View File

@@ -9,46 +9,61 @@ use zeroize::Zeroize;
use crate::{io::IoResultKindHintExt, result::ensure_or}; use crate::{io::IoResultKindHintExt, result::ensure_or};
/// Size of the length prefix header in bytes - equal to the size of a u64
pub const HEADER_SIZE: usize = std::mem::size_of::<u64>(); pub const HEADER_SIZE: usize = std::mem::size_of::<u64>();
#[derive(Error, Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
#[error("Write position is out of buffer bounds")] #[error("Write position is out of buffer bounds")]
/// Error type indicating that a write position is beyond the boundaries of the allocated buffer
pub struct PositionOutOfBufferBounds; pub struct PositionOutOfBufferBounds;
#[derive(Error, Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
#[error("Write position is out of message bounds")] #[error("Write position is out of message bounds")]
/// Error type indicating that a write position is beyond the boundaries of the message
pub struct PositionOutOfMessageBounds; pub struct PositionOutOfMessageBounds;
#[derive(Error, Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
#[error("Write position is out of header bounds")] #[error("Write position is out of header bounds")]
/// Error type indicating that a write position is beyond the boundaries of the header
pub struct PositionOutOfHeaderBounds; pub struct PositionOutOfHeaderBounds;
#[derive(Error, Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
#[error("Message length is bigger than buffer length")] #[error("Message length is bigger than buffer length")]
/// Error type indicating that the message length is larger than the available buffer space
pub struct MessageTooLarge; pub struct MessageTooLarge;
#[derive(Error, Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
/// Error type for message length sanity checks
pub enum MessageLenSanityError { pub enum MessageLenSanityError {
/// Error indicating position is beyond message boundaries
#[error("{0:?}")] #[error("{0:?}")]
PositionOutOfMessageBounds(#[from] PositionOutOfMessageBounds), PositionOutOfMessageBounds(#[from] PositionOutOfMessageBounds),
/// Error indicating message length exceeds buffer capacity
#[error("{0:?}")] #[error("{0:?}")]
MessageTooLarge(#[from] MessageTooLarge), MessageTooLarge(#[from] MessageTooLarge),
} }
#[derive(Error, Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
/// Error type for position bounds checking
pub enum PositionSanityError { pub enum PositionSanityError {
/// Error indicating position is beyond message boundaries
#[error("{0:?}")] #[error("{0:?}")]
PositionOutOfMessageBounds(#[from] PositionOutOfMessageBounds), PositionOutOfMessageBounds(#[from] PositionOutOfMessageBounds),
/// Error indicating position is beyond buffer boundaries
#[error("{0:?}")] #[error("{0:?}")]
PositionOutOfBufferBounds(#[from] PositionOutOfBufferBounds), PositionOutOfBufferBounds(#[from] PositionOutOfBufferBounds),
} }
#[derive(Error, Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
/// Error type combining all sanity check errors
pub enum SanityError { pub enum SanityError {
/// Error indicating position is beyond message boundaries
#[error("{0:?}")] #[error("{0:?}")]
PositionOutOfMessageBounds(#[from] PositionOutOfMessageBounds), PositionOutOfMessageBounds(#[from] PositionOutOfMessageBounds),
/// Error indicating position is beyond buffer boundaries
#[error("{0:?}")] #[error("{0:?}")]
PositionOutOfBufferBounds(#[from] PositionOutOfBufferBounds), PositionOutOfBufferBounds(#[from] PositionOutOfBufferBounds),
/// Error indicating message length exceeds buffer capacity
#[error("{0:?}")] #[error("{0:?}")]
MessageTooLarge(#[from] MessageTooLarge), MessageTooLarge(#[from] MessageTooLarge),
} }
@@ -86,12 +101,16 @@ impl From<PositionSanityError> for SanityError {
} }
} }
/// Result of a write operation on an IO stream
pub struct WriteToIoReturn { pub struct WriteToIoReturn {
/// Number of bytes successfully written in this operation
pub bytes_written: usize, pub bytes_written: usize,
/// Whether the write operation has completed fully
pub done: bool, pub done: bool,
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
/// Length-prefixed encoder that adds a length header to data before writing
pub struct LengthPrefixEncoder<Buf: Borrow<[u8]>> { pub struct LengthPrefixEncoder<Buf: Borrow<[u8]>> {
buf: Buf, buf: Buf,
header: [u8; HEADER_SIZE], header: [u8; HEADER_SIZE],
@@ -99,6 +118,7 @@ pub struct LengthPrefixEncoder<Buf: Borrow<[u8]>> {
} }
impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> { impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
/// Creates a new encoder from a buffer
pub fn from_buffer(buf: Buf) -> Self { pub fn from_buffer(buf: Buf) -> Self {
let (header, pos) = ([0u8; HEADER_SIZE], 0); let (header, pos) = ([0u8; HEADER_SIZE], 0);
let mut r = Self { buf, header, pos }; let mut r = Self { buf, header, pos };
@@ -106,6 +126,7 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
r r
} }
/// Creates a new encoder using the full buffer as a message
pub fn from_message(msg: Buf) -> Self { pub fn from_message(msg: Buf) -> Self {
let mut r = Self::from_buffer(msg); let mut r = Self::from_buffer(msg);
r.restart_write_with_new_message(r.buffer_bytes().len()) r.restart_write_with_new_message(r.buffer_bytes().len())
@@ -113,23 +134,27 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
r r
} }
/// Creates a new encoder using part of the buffer as a message
pub fn from_short_message(msg: Buf, len: usize) -> Result<Self, MessageLenSanityError> { pub fn from_short_message(msg: Buf, len: usize) -> Result<Self, MessageLenSanityError> {
let mut r = Self::from_message(msg); let mut r = Self::from_message(msg);
r.set_message_len(len)?; r.set_message_len(len)?;
Ok(r) Ok(r)
} }
/// Creates a new encoder from buffer, message length and write position
pub fn from_parts(buf: Buf, len: usize, pos: usize) -> Result<Self, SanityError> { pub fn from_parts(buf: Buf, len: usize, pos: usize) -> Result<Self, SanityError> {
let mut r = Self::from_buffer(buf); let mut r = Self::from_buffer(buf);
r.set_msg_len_and_position(len, pos)?; r.set_msg_len_and_position(len, pos)?;
Ok(r) Ok(r)
} }
/// Consumes the encoder and returns the underlying buffer
pub fn into_buffer(self) -> Buf { pub fn into_buffer(self) -> Buf {
let Self { buf, .. } = self; let Self { buf, .. } = self;
buf buf
} }
/// Consumes the encoder and returns buffer, message length and write position
pub fn into_parts(self) -> (Buf, usize, usize) { pub fn into_parts(self) -> (Buf, usize, usize) {
let len = self.message_len(); let len = self.message_len();
let pos = self.writing_position(); let pos = self.writing_position();
@@ -137,11 +162,13 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
(buf, len, pos) (buf, len, pos)
} }
/// Resets the encoder state
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.set_msg_len_and_position(0, 0).unwrap(); self.set_msg_len_and_position(0, 0).unwrap();
self.set_message_offset(0).unwrap(); self.set_message_offset(0).unwrap();
} }
/// Writes the full message to an IO writer, retrying on interrupts
pub fn write_all_to_stdio<W: io::Write>(&mut self, mut w: W) -> io::Result<()> { pub fn write_all_to_stdio<W: io::Write>(&mut self, mut w: W) -> io::Result<()> {
use io::ErrorKind as K; use io::ErrorKind as K;
loop { loop {
@@ -158,6 +185,7 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
} }
} }
/// Writes the next chunk of data to an IO writer and returns number of bytes written and completion status
pub fn write_to_stdio<W: io::Write>(&mut self, mut w: W) -> io::Result<WriteToIoReturn> { pub fn write_to_stdio<W: io::Write>(&mut self, mut w: W) -> io::Result<WriteToIoReturn> {
if self.exhausted() { if self.exhausted() {
return Ok(WriteToIoReturn { return Ok(WriteToIoReturn {
@@ -177,10 +205,12 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
}) })
} }
/// Resets write position to start for restarting output
pub fn restart_write(&mut self) { pub fn restart_write(&mut self) {
self.set_writing_position(0).unwrap() self.set_writing_position(0).unwrap()
} }
/// Resets write position to start and updates message length for restarting with new data
pub fn restart_write_with_new_message( pub fn restart_write_with_new_message(
&mut self, &mut self,
len: usize, len: usize,
@@ -189,6 +219,7 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
.map_err(|e| e.try_into().unwrap()) .map_err(|e| e.try_into().unwrap())
} }
/// Returns the next unwritten slice of data to write from header or message
pub fn next_slice_to_write(&self) -> &[u8] { pub fn next_slice_to_write(&self) -> &[u8] {
let s = self.header_left(); let s = self.header_left();
if !s.is_empty() { if !s.is_empty() {
@@ -203,66 +234,82 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
&[] &[]
} }
/// Returns true if all data including header and message has been written
pub fn exhausted(&self) -> bool { pub fn exhausted(&self) -> bool {
self.next_slice_to_write().is_empty() self.next_slice_to_write().is_empty()
} }
/// Returns slice containing full message data
pub fn message(&self) -> &[u8] { pub fn message(&self) -> &[u8] {
&self.buffer_bytes()[..self.message_len()] &self.buffer_bytes()[..self.message_len()]
} }
/// Returns slice containing written portion of length header
pub fn header_written(&self) -> &[u8] { pub fn header_written(&self) -> &[u8] {
&self.header()[..self.header_offset()] &self.header()[..self.header_offset()]
} }
/// Returns slice containing unwritten portion of length header
pub fn header_left(&self) -> &[u8] { pub fn header_left(&self) -> &[u8] {
&self.header()[self.header_offset()..] &self.header()[self.header_offset()..]
} }
/// Returns slice containing written portion of message data
pub fn message_written(&self) -> &[u8] { pub fn message_written(&self) -> &[u8] {
&self.message()[..self.message_offset()] &self.message()[..self.message_offset()]
} }
/// Returns slice containing unwritten portion of message data
pub fn message_left(&self) -> &[u8] { pub fn message_left(&self) -> &[u8] {
&self.message()[self.message_offset()..] &self.message()[self.message_offset()..]
} }
/// Returns reference to underlying buffer
pub fn buf(&self) -> &Buf { pub fn buf(&self) -> &Buf {
&self.buf &self.buf
} }
/// Returns slice view of underlying buffer bytes
pub fn buffer_bytes(&self) -> &[u8] { pub fn buffer_bytes(&self) -> &[u8] {
self.buf().borrow() self.buf().borrow()
} }
/// Decodes and returns length header value as u64
pub fn decode_header(&self) -> u64 { pub fn decode_header(&self) -> u64 {
u64::from_le_bytes(self.header) u64::from_le_bytes(self.header)
} }
/// Returns slice containing raw length header bytes
pub fn header(&self) -> &[u8; HEADER_SIZE] { pub fn header(&self) -> &[u8; HEADER_SIZE] {
&self.header &self.header
} }
/// Returns decoded message length from header
pub fn message_len(&self) -> usize { pub fn message_len(&self) -> usize {
self.decode_header() as usize self.decode_header() as usize
} }
/// Returns total encoded size including header and message bytes
pub fn encoded_message_bytes(&self) -> usize { pub fn encoded_message_bytes(&self) -> usize {
self.message_len() + HEADER_SIZE self.message_len() + HEADER_SIZE
} }
/// Returns current write position within header and message
pub fn writing_position(&self) -> usize { pub fn writing_position(&self) -> usize {
self.pos self.pos
} }
/// Returns write offset within length header bytes
pub fn header_offset(&self) -> usize { pub fn header_offset(&self) -> usize {
min(self.writing_position(), HEADER_SIZE) min(self.writing_position(), HEADER_SIZE)
} }
/// Returns write offset within message bytes
pub fn message_offset(&self) -> usize { pub fn message_offset(&self) -> usize {
self.writing_position().saturating_sub(HEADER_SIZE) self.writing_position().saturating_sub(HEADER_SIZE)
} }
/// Sets new length header bytes with bounds checking
pub fn set_header(&mut self, header: [u8; HEADER_SIZE]) -> Result<(), MessageLenSanityError> { pub fn set_header(&mut self, header: [u8; HEADER_SIZE]) -> Result<(), MessageLenSanityError> {
self.offset_transaction(|t| { self.offset_transaction(|t| {
t.header = header; t.header = header;
@@ -272,14 +319,17 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
}) })
} }
/// Encodes and sets length header value with bounds checking
pub fn encode_and_set_header(&mut self, header: u64) -> Result<(), MessageLenSanityError> { pub fn encode_and_set_header(&mut self, header: u64) -> Result<(), MessageLenSanityError> {
self.set_header(header.to_le_bytes()) self.set_header(header.to_le_bytes())
} }
/// Sets message lengthwith bounds checking
pub fn set_message_len(&mut self, len: usize) -> Result<(), MessageLenSanityError> { pub fn set_message_len(&mut self, len: usize) -> Result<(), MessageLenSanityError> {
self.encode_and_set_header(len as u64) self.encode_and_set_header(len as u64)
} }
/// Sets write position with message and buffer bounds checking
pub fn set_writing_position(&mut self, pos: usize) -> Result<(), PositionSanityError> { pub fn set_writing_position(&mut self, pos: usize) -> Result<(), PositionSanityError> {
self.offset_transaction(|t| { self.offset_transaction(|t| {
t.pos = pos; t.pos = pos;
@@ -289,20 +339,24 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
}) })
} }
/// Sets write position within header bytes with bounds checking
pub fn set_header_offset(&mut self, off: usize) -> Result<(), PositionOutOfHeaderBounds> { pub fn set_header_offset(&mut self, off: usize) -> Result<(), PositionOutOfHeaderBounds> {
ensure_or(off <= HEADER_SIZE, PositionOutOfHeaderBounds)?; ensure_or(off <= HEADER_SIZE, PositionOutOfHeaderBounds)?;
self.set_writing_position(off).unwrap(); self.set_writing_position(off).unwrap();
Ok(()) Ok(())
} }
/// Sets write position within message bytes with bounds checking
pub fn set_message_offset(&mut self, off: usize) -> Result<(), PositionSanityError> { pub fn set_message_offset(&mut self, off: usize) -> Result<(), PositionSanityError> {
self.set_writing_position(off + HEADER_SIZE) self.set_writing_position(off + HEADER_SIZE)
} }
/// Advances write position by specified offset with bounds checking
pub fn advance(&mut self, off: usize) -> Result<(), PositionSanityError> { pub fn advance(&mut self, off: usize) -> Result<(), PositionSanityError> {
self.set_writing_position(self.writing_position() + off) self.set_writing_position(self.writing_position() + off)
} }
/// Sets message length and write position with bounds checking
pub fn set_msg_len_and_position(&mut self, len: usize, pos: usize) -> Result<(), SanityError> { pub fn set_msg_len_and_position(&mut self, len: usize, pos: usize) -> Result<(), SanityError> {
self.pos = 0; self.pos = 0;
self.set_message_len(len)?; self.set_message_len(len)?;
@@ -347,24 +401,29 @@ impl<Buf: Borrow<[u8]>> LengthPrefixEncoder<Buf> {
} }
impl<Buf: BorrowMut<[u8]>> LengthPrefixEncoder<Buf> { impl<Buf: BorrowMut<[u8]>> LengthPrefixEncoder<Buf> {
/// Gets a mutable reference to the underlying buffer
pub fn buf_mut(&mut self) -> &mut Buf { pub fn buf_mut(&mut self) -> &mut Buf {
&mut self.buf &mut self.buf
} }
/// Gets the buffer as mutable bytes
pub fn buffer_bytes_mut(&mut self) -> &mut [u8] { pub fn buffer_bytes_mut(&mut self) -> &mut [u8] {
self.buf.borrow_mut() self.buf.borrow_mut()
} }
/// Gets a mutable reference to the message slice
pub fn message_mut(&mut self) -> &mut [u8] { pub fn message_mut(&mut self) -> &mut [u8] {
let off = self.message_len(); let off = self.message_len();
&mut self.buffer_bytes_mut()[..off] &mut self.buffer_bytes_mut()[..off]
} }
/// Gets a mutable reference to the written portion of the message
pub fn message_written_mut(&mut self) -> &mut [u8] { pub fn message_written_mut(&mut self) -> &mut [u8] {
let off = self.message_offset(); let off = self.message_offset();
&mut self.message_mut()[..off] &mut self.message_mut()[..off]
} }
/// Gets a mutable reference to the unwritten portion of the message
pub fn message_left_mut(&mut self) -> &mut [u8] { pub fn message_left_mut(&mut self) -> &mut [u8] {
let off = self.message_offset(); let off = self.message_offset();
&mut self.message_mut()[off..] &mut self.message_mut()[off..]

View File

@@ -1,2 +1,4 @@
/// Module that handles decoding functionality
pub mod decoder; pub mod decoder;
/// Module that handles encoding functionality
pub mod encoder; pub mod encoder;