dyn_buf 0.1.0

A dynamic buffer v1 (p1790r0) implement in Rust.
Documentation
//! A dynamic buffer encapsulates memory storage that may be automatically resized
//! as required, where the memory is divided into two regions: readable bytes followed by writable
//! bytes. These memory regions are internal to the dynamic buffer, but direct access to the
//! elements is provided to permit them to be efficiently used with I/O operations.
//!
//! ``` note
//! Note: Such as the send or receive operations of a socket. The readable bytes would be used as
//! the constant buffer sequence for send, and the writable bytes used as the mutable buffer
//! sequence for receive.
//! ```
//!
//! Data written to the writable bytes of a dynamic buffer object is appended to the readable bytes
//! of the same object.

/// `VecBuf` is an effective [dynamic buffer v1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1790r0.html)
/// implement, which tries to reduce reallocation and mem-moving.
///
/// If `commit` and `consume` speed matches(`len()` is always less than `min_write`), this buffer
/// would allocate only once.
///
/// # Example
/// ```
/// use dyn_buf::VecBuf;
/// let mut buf = VecBuf::new(10);
///
/// let t = buf.prepare(4);
/// assert_eq!(t.len(), 4);
///
/// // write data to prepared buffer
/// t[..3].copy_from_slice(&[1, 2, 3]);
/// assert_eq!(buf.data(), &[]);
///
/// buf.commit(3);
/// assert_eq!(buf.data(), &[1, 2, 3]);
///
/// buf.consume(2);
/// assert_eq!(buf.data(), &[3]);
///
/// let t = buf.prepare_at_least(2);
/// assert!(t.len() >= 2);
/// t[..2].copy_from_slice(&[4, 5]);
/// assert_eq!(buf.data(), &[3]);
///
/// buf.commit(2);
/// assert_eq!(buf.data(), &[3, 4, 5]);
///
/// buf.consume(2);
/// assert_eq!(buf.data(), &[5]);
///
/// assert_eq!(buf.into_vec(), vec![5]);
/// ```
#[derive(Default)]
pub struct VecBuf {
    buf: Vec<u8>,
    wrote: usize,
    read: usize,
    min_write: usize,
}

// impl dynamic buffer
impl VecBuf {
    /// Returns the number of readable bytes.
    #[inline]
    pub fn len(&self) -> usize {
        self.wrote - self.read
    }

    /// Returns `true` if buffer contains no readable bytes.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.read >= self.wrote
    }

    /// Returns the maximum number of bytes, both readable and writable, that can be held by `self`
    /// without requiring reallocation.
    pub fn capacity(&self) -> usize {
        self.buf.len() - self.len()
    }

    /// Returns a constant buffer sequence u that represents the readable bytes.
    #[inline]
    pub fn data(&self) -> &[u8] {
        &self.buf[self.read..self.wrote]
    }

    /// Returns a mutable buffer sequence u representing the writable bytes, and where
    /// `buffer_size(u) == amt`.
    ///
    /// The dynamic buffer reallocates memory as required. All constant or mutable buffer sequences
    /// previously obtained using data() or prepare() are invalidated.
    ///
    /// Panic: length_error if size() + `amt` exceeds max_size().
    pub fn prepare(&mut self, amt: usize) -> &mut [u8] {
        self.reserve(amt);
        &mut self.buf[self.wrote..self.wrote + amt]
    }

    /// Returns a mutable buffer sequence u representing the writable bytes, and where
    /// `buffer_size(u) >= amt`.
    ///
    /// The dynamic buffer reallocates memory as required. All constant or mutable buffer sequences
    /// previously obtained using data() or prepare() are invalidated.
    ///
    /// Panic: length_error if size() + `amt` exceeds max_size().
    pub fn prepare_at_least(&mut self, amt: usize) -> &mut [u8] {
        self.reserve(amt);
        &mut self.buf[self.wrote..]
    }

    /// Appends `amt` bytes from the start of the writable bytes to the end of the readable bytes.
    ///
    /// The remainder of the writable bytes are discarded. If `amt` is greater than the number of
    /// writable bytes, all writable bytes are appended to the readable bytes. All constant
    /// or mutable buffer sequences previously obtained using data() or prepare() are invalidated.
    #[inline]
    pub fn commit(&mut self, amt: usize) {
        debug_assert!(self.wrote + amt <= self.buf.len());
        self.wrote += amt
    }

    /// Removes `amt` bytes from beginning of the readable bytes.
    ///
    /// If `amt` is greater than the number of readable bytes, all readable bytes are removed. All
    /// constant or mutable buffer sequences previously obtained using data() or prepare() are
    /// invalidated.
    #[inline]
    pub fn consume(&mut self, amt: usize) {
        debug_assert!(amt <= self.len());
        if amt >= self.len() {
            self.wrote = 0;
            self.read = 0;
        } else {
            self.read += amt;
        }
    }
}

// impl helpers
impl VecBuf {
    /// create a `VecBuf` with `min_write`
    ///
    /// `prepare_at_least` will return a buffer at least `min_write` bytes.
    /// # Example
    ///```
    /// use dyn_buf::VecBuf;
    /// let min_write = 5;
    /// let mut buf = VecBuf::new(min_write);
    /// let t = buf.prepare_at_least(0);
    /// assert!(t.len() >= min_write);
    /// t[..2].copy_from_slice(&[1,2]);
    /// buf.commit(2);
    /// let t = buf.prepare_at_least(0);
    /// assert!(t.len() >= min_write);
    /// ```
    pub fn new(min_write: usize) -> Self {
        Self {
            min_write,
            ..Default::default()
        }
    }

    /// Reserves capacity for at least `amt` bytes to be wrote
    pub fn reserve(&mut self, amt: usize) {
        let amt = amt.max(if self.buf.is_empty() {
            self.min_write * 2
        } else {
            self.min_write
        });

        if self.buf.len() < self.wrote + amt {
            if self.buf.len() >= self.len() + amt {
                self.move_data_to_front();
                return;
            }
            self.grow(amt);
        }
    }

    fn move_data_to_front(&mut self) {
        self.buf.copy_within(self.read..self.wrote, 0);
        self.wrote -= self.read;
        self.read = 0;
    }

    /// Grow capacity at least `amt` bytes
    pub fn grow(&mut self, amt: usize) {
        self.buf.reserve(amt.max(self.buf.len()));
        self.buf.resize(self.buf.capacity(), 0);
    }

    /// Write all bytes of `buf` into `self`
    pub fn write_all(&mut self, buf: &[u8]) {
        self.prepare(buf.len()).copy_from_slice(buf);
        self.commit(buf.len());
    }

    /// Converts `self` into a vector without clones or allocation. The resulting vector contains
    /// all the readable bytes
    pub fn into_vec(mut self) -> Vec<u8> {
        if self.read > 0 {
            self.move_data_to_front();
        }
        self.buf.truncate(self.wrote);
        self.buf
    }
}