RingBuffer

Struct RingBuffer 

Source
pub struct RingBuffer<T> { /* private fields */ }
Expand description

A fixed-sized collection meant to hold a limited horizon of generic data. When filled to capacity, older data will be overwritten.

Indexing and iterating over this collection will start from the most recent element (assuming you primarily use push, however all iterators implement ExactSizeIterator and DoubleEndedIterator, so they can be trivially traversed backwards with the rev method.

Be aware that the Eq and PartialEq implementations for this struct do not care about buffer rotation (where in the ring a sequence starts), but they do check if two buffers have the same capacity. So two buffers with the sequence [1,2,3] may not compare as equal if one can hold 10 elements and one can hold 20. If you want to compare these, a convenience method called elem_equal is provided.

Implementations§

Source§

impl<T> RingBuffer<T>

Source

pub fn cap(&self) -> usize

The capacity of the buffer, this is the most data this buffer can store before it starts overwriting older entries.

Source

pub fn len(&self) -> usize

The length of the buffer. This is the number of elements currently stores. When len and cap are equal, the buffer will begin overwriting older entries.

Source

pub fn new(cap: usize) -> Self

Creates a new RingBuffer at the given capacity, this buffer will not grow without explicit calls to resize.

Source

pub fn from_exact_size_iter<I, U>(iter: I) -> Self
where I: IntoIterator<Item = T, IntoIter = U>, U: ExactSizeIterator<Item = T>,

Creates a new RingBuffer that exactly fits the data in the provided iterator. It must have an exact size or we cannot intuit the capacity.

use simple_ringbuf::RingBuffer;;

let buf = RingBuffer::from_exact_size_iter(vec![1,2,3]);
assert!(buf.is_justified());

let mut cmp = RingBuffer::new(3);
cmp.push(1);
cmp.push(2);
cmp.push(3);

assert_eq!(buf, cmp);
Source

pub fn from_iter_cap<I>( iter: I, cap: usize, ) -> (Self, Option<impl Iterator<Item = T>>)
where I: IntoIterator<Item = T>,

Creates a new RingBuffer with capacity cap that fills itself with at most cap elements from the provided iterator. If any of the iterator is left over at the end, an iterator yielding those elements will be returned.

use simple_ringbuf::RingBuffer;;

let (buf, rem) = RingBuffer::from_iter_cap(vec![1,2,3], 2);
assert!(buf.is_justified());

let mut cmp = RingBuffer::new(2);
cmp.push(1);
cmp.push(2);

assert_eq!(buf, cmp);

assert!(rem.is_some());
let rem = rem.unwrap();
assert_eq!(vec![3], rem.collect::<Vec<_>>());
Source

pub fn push(&mut self, elem: T) -> Option<T>

Pushes an element onto the collection. This is intended to be the primary means of using this as a log/undo buffer.

If the buffer is full, this will overwrite the element at buf[len-1], which is the “oldest” element if you generally use the collection as designed.

If this method overwrites an existing element it will return it, otherwise it will return None.

use simple_ringbuf::RingBuffer;;

let mut buf = RingBuffer::new(3);

buf.push(1);
buf.push(2);
buf.push(3);

assert_eq!(buf[0], 3);
assert_eq!(buf[1], 2);
assert_eq!(buf[2], 1);

let el = buf.push(10);
assert_eq!(el, Some(1));
assert_eq!(buf[0], 10);
assert_eq!(buf[1], 3);
assert_eq!(buf[2], 2);
Source

pub fn push_back(&mut self, elem: T) -> Option<T>

Pushes an element as if it were the first element added. If the buffer is full, this will overwrite the element at buf[0], which is the most recently added element (if you use the collection as designed defaulting to push in most cases).

This is not intended to be the primary method of adding data, but rather reinserting an element you’ve removed or otherwise rewinding history.

If this method overwrites an existing element, it will return it. Otherwise it will return None.

use simple_ringbuf::RingBuffer;;

let mut buf = RingBuffer::new(3);

buf.push(1);
buf.push(2);
buf.push(3);

assert_eq!(buf[0], 3);
assert_eq!(buf[1], 2);
assert_eq!(buf[2], 1);

let el = buf.push(10);
assert!(el.is_some());
let el = el.unwrap();

let el = buf.push_back(el);
assert_eq!(el, Some(10));
assert_eq!(buf[0], 3);
assert_eq!(buf[1], 2);
assert_eq!(buf[2], 1);
Source

pub fn pop(&mut self) -> Option<T>

Removes the most recently added element from the collection and returns it, shrinking the buffer from the end.

Note that if you’ve been using push_back this won’t be the most recently added element per se, but rather the element at the end of the collection (aka at buf[0]).

use simple_ringbuf::RingBuffer;

let mut buf = RingBuffer::new(5);
buf.push(5);
buf.push(10);
buf.push(20);

assert_eq!(buf.pop(), Some(20));
assert_eq!(buf.len(), 2);
Source

pub fn pop_oldest(&mut self) -> Option<T>

Removes the oldest element from the collection and returns it, shrinking the buffer from the beginning.

Note that if you’ve been using push_back this won’t be the oldest element per se, but rather the element at the [beginning] (buf[len-1]).

use simple_ringbuf::RingBuffer;

let mut buf = RingBuffer::new(5);
buf.push(5);
buf.push(10);
buf.push(20);

assert_eq!(buf.pop_oldest(), Some(5));
assert_eq!(buf.len(), 2);
Source

pub fn is_empty(&self) -> bool

Determines whether the buffer is empty.

Source

pub fn is_full(&self) -> bool

Determines whether the buffer is filled to capacity, if this is true, any subsequent writes will overwrite the oldest element.

Source

pub fn iter(&self) -> RingBufIter<'_, T>

Returns an iterator over this buffer.

Source

pub fn justify(&mut self)

Forces a buffer to be “justified”. This means the first element is at the beginning of the actual underlying buffer. Once a buffer gets full, or if you frequently use pop_oldest, this will rarely be true.

Justifying a buffer is largely useful for internal operations such as resize, but may be useful if you require the elements to be in a contiguous memory block for some reason.

use simple_ringbuf::RingBuffer;

let mut buf = RingBuffer::new(5);

buf.push(19);
buf.push(26);
buf.push(113);

assert!(buf.is_justified());

// Buf now has a gap
buf.pop_oldest();
assert!( !buf.is_justified() );

buf.justify();
assert!(buf.is_justified());
Source

pub fn is_contiguous(&self) -> bool

Determines if a buffer is “contiguous” if the end of the buffer is after the beginning in the internal memory layout. That is beginning < end.

This likely isn’t useful in most cases, but if you want to do unsafe hacky things, or make sure the buffer is contiguous before iterating for, e.g., cache reasons you may decide to call this before deciding whether to call justify. (This likely won’t have any appreciable effect on speed, especially while iterating in the default order).

An empty buffer is always contiguous.

Source

pub fn beginning(&self) -> Option<usize>

Shows where in the internal buffer the current data begins, not particularly useful but here for convenience. This will return None when the buffer is empty. Note that due to how indexing works, this is buf[end], buf[0] will yield the newest element added.

Source

pub fn end(&self) -> Option<usize>

Shows where in the internal buffer the current data ends, not particularly useful but here for convenience. This will return None when the buffer is empty. Note that due to how indexing works, this is buf[0], buf[end] will yield the oldest element added.

Source

pub fn is_justified(&self) -> bool

Determines if the buffer is “justified”, this means the first element is at the beginning of the actual underlying buffer. Once a buffer gets full, or if you frequently use pop_oldest, this will rarely be true.

An empty buffer is always justified.

use simple_ringbuf::RingBuffer;
let mut buf = RingBuffer::new(5);

buf.push(19);
buf.push(26);
buf.push(113);

assert!(buf.is_justified());

buf.pop();
assert!(buf.is_justified());

// Buf now has a gap
buf.pop_oldest();
assert!( !buf.is_justified() );

// Empty buffer
buf.pop();
assert!(buf.is_justified());

This is largely useful for internal operations such as resize. If you really need to check for something that will aid, e.g., iteration speed, or you want to do unsafe hacky things, is_contiguous is probably closer to what you want.

Source

pub fn resize(&mut self, new_cap: usize)

Resizes the buffer such that it can hold more or fewer total elements. This will panic is the capacity underflows the current length.

The new buffer will be justified.

use simple_ringbuf::RingBuffer;

let mut buf = RingBuffer::new(5);
buf.push(2);
buf.push(3);

buf.resize(2);
assert_eq!(buf.cap(), 2);

buf.pop_oldest();
buf.resize(9);

assert_eq!(buf.cap(), 9);
assert_eq!(buf.len(), 1);
assert!(buf.is_justified());
Source

pub fn shrink_to_fit(&mut self)

Source§

impl<T> RingBuffer<T>
where T: PartialEq,

Source

pub fn elem_equal(&self, other: &Self) -> bool

Performs an element-wise comparison between two different-capacity buffers. If your buffers are the same size you probably just want ==.

use simple_ringbuf::RingBuffer;

let mut buf = RingBuffer::new(5);
buf.push(1);
buf.push(2);
buf.push(3);

let mut buf2 = RingBuffer::new(10);
buf2.push(1);
buf2.push(2);
buf2.push(3);

assert_ne!(buf, buf2); // Not the same!
assert!(buf.elem_equal(&buf2)); // This works though

Trait Implementations§

Source§

impl<T> Clone for RingBuffer<T>
where T: Clone,

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T> Debug for RingBuffer<T>
where T: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<T> Drop for RingBuffer<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T> Index<usize> for RingBuffer<T>

Source§

type Output = T

The returned type after indexing.
Source§

fn index(&self, idx: usize) -> &T

Performs the indexing (container[index]) operation. Read more
Source§

impl<'a, T> IntoIterator for &'a RingBuffer<T>

Source§

type Item = &'a T

The type of the elements being iterated over.
Source§

type IntoIter = RingBufIter<'a, T>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T> IntoIterator for RingBuffer<T>

Source§

type Item = T

The type of the elements being iterated over.
Source§

type IntoIter = RingBufIntoIter<T>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T> PartialEq for RingBuffer<T>
where T: PartialEq,

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T> Eq for RingBuffer<T>
where T: Eq,

Auto Trait Implementations§

§

impl<T> Freeze for RingBuffer<T>

§

impl<T> RefUnwindSafe for RingBuffer<T>
where T: RefUnwindSafe,

§

impl<T> !Send for RingBuffer<T>

§

impl<T> !Sync for RingBuffer<T>

§

impl<T> Unpin for RingBuffer<T>

§

impl<T> UnwindSafe for RingBuffer<T>
where T: RefUnwindSafe,

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.