limq 0.4.0

Queue with a controller for monitoring queue elements
Documentation
use std::{cmp, collections::VecDeque};

use super::{BufQStats, CheckErr, Controller};


/// A [`Controller`] for queue of `Vec<u8>` that can optionally limit the
/// queue length as well as total buffer size.
pub struct BufLim {
  cur_len: usize,
  max_len: Option<usize>,
  len_hwm: usize,
  cur_size: usize,
  max_size: Option<usize>,
  size_hwm: usize
}

impl BufLim {
  /// Create a new object for limiting a buffers queue to a configured length
  /// and size.
  ///
  /// # Panics
  /// `max_len` must not be `0`.  `max_size` must not be `0`.
  #[must_use]
  pub fn new(max_len: Option<usize>, max_size: Option<usize>) -> Self {
    assert!(!matches!(max_len, Some(0)), "zero-length limit");
    assert!(!matches!(max_size, Some(0)), "zero-size limit");
    Self {
      cur_len: 0,
      max_len,
      len_hwm: 0,
      cur_size: 0,
      max_size,
      size_hwm: 0
    }
  }

  /// Return the current total size of all buffers in queue.
  #[must_use]
  pub const fn size(&self) -> usize {
    self.cur_size
  }

  /// Return the current maximum queue length configuration.
  #[must_use]
  pub const fn get_max_len(&self) -> Option<usize> {
    self.max_len
  }

  /// Return the current maximum total buffer size configuration.
  #[must_use]
  pub const fn get_max_size(&self) -> Option<usize> {
    self.max_size
  }

  /// # Panics
  /// `max_len` must not be `0`.
  pub fn set_max_len(&mut self, max_len: Option<usize>) {
    assert!(!matches!(max_len, Some(0)), "zero-length limit");
    self.max_len = max_len;
  }

  /// # Panics
  /// `max_size` must not be `0`.
  pub fn set_max_size(&mut self, max_size: Option<usize>) {
    assert!(!matches!(max_size, Some(0)), "zero-size limit");
    self.max_size = max_size;
  }

  /// Return queue statistics.
  #[must_use]
  pub const fn stats(&self) -> BufQStats {
    BufQStats {
      len: self.cur_len,
      len_hwm: self.len_hwm,
      size: self.cur_size,
      size_hwm: self.size_hwm
    }
  }

  /// Set length and size high-water marks to the current length/size values.
  pub const fn reset_hwm(&mut self) {
    self.len_hwm = self.cur_len;
    self.size_hwm = self.cur_size;
  }

  /// Set length and size high-water marks to `0`.
  pub const fn clear_hwm(&mut self) {
    self.len_hwm = 0;
    self.size_hwm = 0;
  }
}

impl Controller for BufLim {
  type Item = Vec<u8>;

  fn size_hint(&self) -> Option<usize> {
    self.max_len
  }

  fn is_full(&self, q: &VecDeque<Self::Item>) -> bool {
    self.max_len.is_some_and(|max_len| q.len() >= max_len)
      || self
        .max_size
        .is_some_and(|max_size| self.cur_size >= max_size)
  }

  fn is_overflow(&self, q: &VecDeque<Self::Item>) -> bool {
    self.max_len.is_some_and(|max_len| q.len() > max_len)
      || self
        .max_size
        .is_some_and(|max_size| self.cur_size > max_size)
  }

  fn check(
    &self,
    q: &VecDeque<Self::Item>,
    n: &Self::Item
  ) -> Result<(), CheckErr> {
    if let Some(max_len) = self.max_len {
      if q.len() + 1 > max_len {
        return Err(CheckErr::WontFit);
      }
    }
    if let Some(max_size) = self.max_size {
      if n.len() > max_size {
        return Err(CheckErr::CantFit);
      }
      if self.cur_size + n.len() > max_size {
        return Err(CheckErr::WontFit);
      }
    }
    Ok(())
  }

  fn reg(&mut self, q: &VecDeque<Self::Item>, n: &Self::Item) {
    self.cur_len += 1;

    self.len_hwm = cmp::max(self.len_hwm, q.len());

    // At this point it has been determined that the new buffer will not
    // overflow the queue.  Register the buffer size and return true to tell
    // caller to add the buffer.
    self.cur_size += n.len();

    self.size_hwm = cmp::max(self.size_hwm, self.cur_size);
  }

  fn dereg(&mut self, n: &Self::Item) {
    self.cur_len -= 1;
    self.cur_size -= n.len();
  }
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :