Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7684d50d6ede
Choose a base ref
...
head repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f65bc8aa7910
Choose a head ref
  • 3 commits
  • 1 file changed
  • 1 contributor

Commits on Sep 22, 2017

  1. Copy the full SHA
    7b29dfe View commit details
  2. Add RingBuffer::{enqueue_allocated,dequeue_allocated}.

    These should be used instead of enqueue_many because they do not
    require the caller to handle wraparound explicitly.
    whitequark committed Sep 22, 2017
    Copy the full SHA
    3c74d33 View commit details
  3. Make sure all side-effectful RingBuffer methods are #[must_use].

    Some of them already use Result, but the ones that can return
    an empty slice (or a slice shorter than requested) also must have
    their return value (at least) checked.
    whitequark committed Sep 22, 2017
    Copy the full SHA
    f65bc8a View commit details
Showing with 106 additions and 3 deletions.
  1. +106 −3 src/storage/ring_buffer.rs
109 changes: 106 additions & 3 deletions src/storage/ring_buffer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Uncomment the #[must_use]s here once [RFC 1940] hits stable.
// [RFC 1940]: https://github.com/rust-lang/rust/issues/43302

use core::cmp;
use managed::ManagedSlice;

@@ -157,6 +160,7 @@ impl<'a, T: 'a> RingBuffer<'a, T> {
///
/// This function may return a slice smaller than the given size
/// if the free space in the buffer is not contiguous.
// #[must_use]
pub fn enqueue_many<'b>(&'b mut self, size: usize) -> &'b mut [T] {
self.enqueue_many_with(|buf| {
let size = cmp::min(size, buf.len());
@@ -166,6 +170,7 @@ impl<'a, T: 'a> RingBuffer<'a, T> {

/// Enqueue as many elements from the given slice into the buffer as possible,
/// and return the amount of elements that could fit.
// #[must_use]
pub fn enqueue_slice(&mut self, data: &[T]) -> usize
where T: Copy {
let (size_1, data) = self.enqueue_many_with(|buf| {
@@ -203,6 +208,7 @@ impl<'a, T: 'a> RingBuffer<'a, T> {
///
/// This function may return a slice smaller than the given size
/// if the allocated space in the buffer is not contiguous.
// #[must_use]
pub fn dequeue_many<'b>(&'b mut self, size: usize) -> &'b mut [T] {
self.dequeue_many_with(|buf| {
let size = cmp::min(size, buf.len());
@@ -212,6 +218,7 @@ impl<'a, T: 'a> RingBuffer<'a, T> {

/// Dequeue as many elements from the buffer into the given slice as possible,
/// and return the amount of elements that could fit.
// #[must_use]
pub fn dequeue_slice(&mut self, data: &mut [T]) -> usize
where T: Copy {
let (size_1, data) = self.dequeue_many_with(|buf| {
@@ -230,12 +237,10 @@ impl<'a, T: 'a> RingBuffer<'a, T> {

/// This is the "random access" ring buffer interface: it operates with element slices,
/// and allows to access elements of the buffer that are not adjacent to its head or tail.
///
/// After calling these functions to inject or extract elements, one would normally
/// use the `enqueue_many` or `dequeue_many` methods to adjust the head or tail.
impl<'a, T: 'a> RingBuffer<'a, T> {
/// Return the largest contiguous slice of unallocated buffer elements starting
/// at the given offset past the last allocated element, and up to the given size.
// #[must_use]
pub fn get_unallocated(&mut self, offset: usize, mut size: usize) -> &mut [T] {
let start_at = (self.read_at + self.length + offset) % self.capacity();
// We can't access past the end of unallocated data.
@@ -250,8 +255,39 @@ impl<'a, T: 'a> RingBuffer<'a, T> {
&mut self.storage[start_at..start_at + size]
}

/// Write as many elements from the given slice into unallocated buffer elements
/// starting at the given offset past the last allocated element, and return
/// the amount written.
// #[must_use]
pub fn write_unallocated(&mut self, offset: usize, data: &[T]) -> usize
where T: Copy {
let (size_1, offset, data) = {
let slice = self.get_unallocated(offset, data.len());
let slice_len = slice.len();
slice.copy_from_slice(&data[..slice_len]);
(slice_len, offset + slice_len, &data[slice_len..])
};
let size_2 = {
let slice = self.get_unallocated(offset, data.len());
let slice_len = slice.len();
slice.copy_from_slice(&data[..slice_len]);
slice_len
};
size_1 + size_2
}

/// Enqueue the given number of unallocated buffer elements.
///
/// # Panics
/// Panics if the number of elements given exceeds the number of unallocated elements.
pub fn enqueue_unallocated(&mut self, count: usize) {
assert!(count <= self.window());
self.length += count;
}

/// Return the largest contiguous slice of allocated buffer elements starting
/// at the given offset past the first allocated element, and up to the given size.
// #[must_use]
pub fn get_allocated(&self, offset: usize, mut size: usize) -> &[T] {
let start_at = (self.read_at + offset) % self.capacity();
// We can't read past the end of the allocated data.
@@ -265,6 +301,35 @@ impl<'a, T: 'a> RingBuffer<'a, T> {

&self.storage[start_at..start_at + size]
}

/// Read as many elements from allocated buffer elements into the given slice
/// starting at the given offset past the first allocated element, and return
/// the amount read.
// #[must_use]
pub fn read_allocated(&mut self, offset: usize, data: &mut [T]) -> usize
where T: Copy {
let (size_1, offset, data) = {
let slice = self.get_allocated(offset, data.len());
data[..slice.len()].copy_from_slice(slice);
(slice.len(), offset + slice.len(), &mut data[slice.len()..])
};
let size_2 = {
let slice = self.get_allocated(offset, data.len());
data[..slice.len()].copy_from_slice(slice);
slice.len()
};
size_1 + size_2
}

/// Dequeue the given number of allocated buffer elements.
///
/// # Panics
/// Panics if the number of elements given exceeds the number of allocated elements.
pub fn dequeue_allocated(&mut self, count: usize) {
assert!(count <= self.len());
self.length -= count;
self.read_at = (self.read_at + count) % self.capacity();
}
}

impl<'a, T: 'a> From<ManagedSlice<'a, T>> for RingBuffer<'a, T> {
@@ -560,6 +625,22 @@ mod test {
assert_eq!(&ring.storage[..], b"ABCDEFGHIJKL");
}

#[test]
fn test_buffer_write_unallocated() {
let mut ring = RingBuffer::new(vec![b'.'; 12]);
ring.enqueue_many(6).copy_from_slice(b"abcdef");
ring.dequeue_many(6).copy_from_slice(b"ABCDEF");

assert_eq!(ring.write_unallocated(0, b"ghi"), 3);
assert_eq!(&ring.storage[..], b"ABCDEFghi...");

assert_eq!(ring.write_unallocated(3, b"jklmno"), 6);
assert_eq!(&ring.storage[..], b"mnoDEFghijkl");

assert_eq!(ring.write_unallocated(9, b"pqrstu"), 3);
assert_eq!(&ring.storage[..], b"mnopqrghijkl");
}

#[test]
fn test_buffer_get_allocated() {
let mut ring = RingBuffer::new(vec![b'.'; 12]);;
@@ -577,4 +658,26 @@ mod test {
ring.enqueue_slice(b"abcd");
assert_eq!(ring.get_allocated(4, 8), b"ijkl");
}

#[test]
fn test_buffer_read_allocated() {
let mut ring = RingBuffer::new(vec![b'.'; 12]);
ring.enqueue_many(12).copy_from_slice(b"abcdefghijkl");

let mut data = [0; 6];
assert_eq!(ring.read_allocated(0, &mut data[..]), 6);
assert_eq!(&data[..], b"abcdef");

ring.dequeue_many(6).copy_from_slice(b"ABCDEF");
ring.enqueue_many(3).copy_from_slice(b"mno");

let mut data = [0; 6];
assert_eq!(ring.read_allocated(3, &mut data[..]), 6);
assert_eq!(&data[..], b"jklmno");

let mut data = [0; 6];
assert_eq!(ring.read_allocated(6, &mut data[..]), 3);
assert_eq!(&data[..], b"mno\x00\x00\x00");

}
}