tools/byte_buffer: add examples and docs

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2020-07-03 11:56:41 +02:00 committed by Dietmar Maurer
parent 6fffca783e
commit c734a627a8

View File

@ -6,7 +6,6 @@
//! ```
//! # use std::io::Read;
//! # use proxmox::tools::byte_buffer::ByteBuffer;
//!
//! fn code<T: Read>(input: &mut T) -> std::io::Result<Box<[u8]>> {
//! let mut buffer = ByteBuffer::new();
//! let amount = buffer.read_from(input)?;
@ -23,6 +22,10 @@ use crate::tools::vec;
use tokio::io::AsyncReadExt;
/// A Buffer that holds bytes (u8)
/// has convenience methods for reading (with any reader that
/// implements std::io::Read or tokio::io::AsyncRead) onto the back
/// and consuming from the front
pub struct ByteBuffer {
buf: Box<[u8]>,
data_size: usize,
@ -30,6 +33,8 @@ pub struct ByteBuffer {
}
impl ByteBuffer {
/// Creates a new instance with a default capacity of 4096
pub fn new() -> Self {
Self::with_capacity(4096)
}
@ -42,6 +47,7 @@ impl ByteBuffer {
}
}
/// Returns the length of the data in the Buffer
pub fn data_size(&self) -> usize {
self.data_size
}
@ -58,6 +64,25 @@ impl ByteBuffer {
self.data_size >= self.capacity
}
/// Sets the length of the data. Useful if data was manually added
/// with a mutable slice (e.g. from [get_free_mut_slice](#method.get_free_mut_slice)).
///
/// Panics when new size would be greater than capacity.
///
/// Example:
/// ```
/// # use proxmox::tools::byte_buffer::ByteBuffer;
/// let mut buf = ByteBuffer::new();
/// buf.get_free_mut_slice()[..1].copy_from_slice(&[1u8]);
/// buf.add_size(1);
/// ```
///
/// This code will panic:
/// ```should_panic
/// # use proxmox::tools::byte_buffer::ByteBuffer;
/// let mut buf = ByteBuffer::with_capacity(128);
/// buf.add_size(256);
/// ```
pub fn add_size(&mut self, size: usize) {
if self.data_size + size > self.capacity {
panic!("size bigger than capacity!");
@ -65,14 +90,45 @@ impl ByteBuffer {
self.data_size += size;
}
/// Gets an immutable reference to the data in the buffer
/// Example:
/// ```
/// # use proxmox::tools::byte_buffer::ByteBuffer;
/// let mut buf = ByteBuffer::new();
/// buf.get_free_mut_slice()[..2].copy_from_slice(&[1u8, 2u8]);
/// buf.add_size(2);
/// assert_eq!(buf.get_data_slice(), &[1u8, 2u8]);
/// ```
pub fn get_data_slice(&self) -> &[u8] {
&self.buf[..self.data_size]
}
/// Returns a mutable reference to the free section of the
/// Buffer. There are no guarantees about the content of the
/// free part of the Buffer (may even be uninitialized).
/// see [add_size](#method.add_size) for a usage example.
pub fn get_free_mut_slice(&mut self) -> &mut [u8] {
&mut self.buf[self.data_size..self.capacity]
}
/// Consumes up to max_amount of data from the front
/// of the buffer. If there was less than max_amount present,
/// it will return as much data as there was in the buffer.
/// The rest of the data will be moved to the front, and
/// the data size will be updated accordingly.
///
/// Example:
/// ```
/// # use proxmox::tools::byte_buffer::ByteBuffer;
/// let mut buf = ByteBuffer::new();
/// buf.get_free_mut_slice()[..2].copy_from_slice(&[1u8, 2u8]);
/// buf.add_size(2);
/// assert_eq!(buf.data_size(), 2);
///
/// let data = buf.consume(100);
/// assert_eq!(data, vec![1u8, 2u8].into_boxed_slice());
/// assert!(buf.is_empty());
/// ```
pub fn consume(&mut self, max_amount: usize) -> Box<[u8]> {
let size = min(max_amount, self.data_size);
let mut tmp = Vec::with_capacity(size);
@ -82,12 +138,27 @@ impl ByteBuffer {
tmp.into_boxed_slice()
}
/// Takes a reader and reads into the back of the buffer (up to the
/// free space in the buffer) and updates its size accordingly.
///
/// Example:
/// ```norun
/// // create some reader
/// let reader = ...;
///
/// let mut buf = ByteBuffer::new();
/// let res = buf.read_from(reader);
/// // do something with the buffer
/// ...
/// ```
pub fn read_from<T: Read>(&mut self, input: &mut T) -> Result<usize> {
let amount = input.read(self.get_free_mut_slice())?;
self.add_size(amount);
Ok(amount)
}
/// Same as read_from, but for reader that implement tokio::io::AsyncRead.
/// See [read_from](#method.read_from) for an example
pub async fn read_from_async<T: AsyncReadExt + Unpin>(&mut self, input: &mut T) -> Result<usize> {
let amount = input.read(self.get_free_mut_slice()).await?;
self.add_size(amount);