diff --git a/README.md b/README.md index d0818bd..44dcfb9 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,11 @@ The ringbuffer crate provides safe fixed size circular buffers (ringbuffers) in Implementations for three kinds of ringbuffers, with a mostly similar API are provided: -| type | description | -| --- | --- | -| `AllocRingBuffer` | Ringbuffer allocated on the heap at runtime. This ringbuffer is still fixed size and requires alloc. | -| `ConstGenericRingBuffer` | Ringbuffer which uses const generics to allocate on the stack. | +| type | description | +|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `AllocRingBuffer` | Ringbuffer allocated on the heap at runtime. This ringbuffer is still fixed size. This requires alloc and the alloc feature. | +| `GrowableAllocRingBuffer` | Ringbuffer allocated on the heap at runtime. This ringbuffer can grow in size, and is implemented as an `alloc::VecDeque` internally. This requires alloc and the alloc feature. | +| `ConstGenericRingBuffer` | Ringbuffer which uses const generics to allocate on the stack. | All of these ringbuffers also implement the RingBuffer trait for their shared API surface. @@ -44,9 +45,9 @@ fn main() { # Features -| name | default | description | -| --- | --- | --- | -| alloc | ✓ | Disable this feature to remove the dependency on alloc. The feature is compatible with `no_std`. | +| name | default | description | +|-------|---------|--------------------------------------------------------------------------------------------------------------| +| alloc | ✓ | Disable this feature to remove the dependency on alloc. Disabling this feature makes `ringbuffer` `no_std`. | # License diff --git a/benches/bench.rs b/benches/bench.rs index 8d843b7..fe85c15 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,8 +1,8 @@ #![cfg(not(tarpaulin))] use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion}; -use ringbuffer::{AllocRingBuffer, ConstGenericRingBuffer, RingBufferExt, RingBufferWrite}; +use ringbuffer::{AllocRingBuffer, ConstGenericRingBuffer, RingBuffer}; -fn benchmark_push, F: Fn() -> T>(b: &mut Bencher, new: F) { +fn benchmark_push, F: Fn() -> T>(b: &mut Bencher, new: F) { b.iter(|| { let mut rb = new(); @@ -15,7 +15,7 @@ fn benchmark_push, F: Fn() -> T>(b: &mut Bencher, new: F) }) } -fn benchmark_push_dequeue, F: Fn() -> T>(b: &mut Bencher, new: F) { +fn benchmark_push_dequeue, F: Fn() -> T>(b: &mut Bencher, new: F) { b.iter(|| { let mut rb = new(); @@ -49,7 +49,7 @@ fn benchmark_push_dequeue, F: Fn() -> T>(b: &mut Bencher, }) } -fn benchmark_various, F: Fn() -> T>(b: &mut Bencher, new: F) { +fn benchmark_various, F: Fn() -> T>(b: &mut Bencher, new: F) { b.iter(|| { let mut rb = new(); diff --git a/src/lib.rs b/src/lib.rs index 931ee04..37074a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,66 +11,15 @@ #![deny(clippy::doc_markdown)] #![deny(clippy::semicolon_if_nothing_returned)] #![allow(unused_unsafe)] // to support older rust versions -//! # Ringbuffer -//! ![Github Workflows](https://img.shields.io/github/workflow/status/NULLx76/ringbuffer/Rust?logo=github&style=for-the-badge) -//! [![Codecov](https://img.shields.io/codecov/c/github/NULLx76/ringbuffer?logo=codecov&style=for-the-badge)](https://codecov.io/gh/NULLx76/ringbuffer) -//! [![Docs.rs](https://img.shields.io/badge/docs.rs-ringbuffer-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K)](https://docs.rs/ringbuffer) -//! [![Crates.io](https://img.shields.io/crates/v/ringbuffer?logo=rust&style=for-the-badge)](https://crates.io/crates/ringbuffer) -//! -//! The ringbuffer crate provides safe fixed size circular buffers (ringbuffers) in rust. -//! -//! Implementations for three kinds of ringbuffers, with a mostly similar API are provided: -//! -//! | type | description | -//! | --- | --- | -//! | [`AllocRingBuffer`] | Ringbuffer allocated on the heap at runtime. This ringbuffer is still fixed size and requires alloc. | -//! | [`ConstGenericRingBuffer`] | Ringbuffer which uses const generics to allocate on the stack. | -//! -//! All of these ringbuffers also implement the [`RingBuffer`] trait for their shared API surface. -//! -//! # Usage -//! -//! ``` -//! use ringbuffer::{AllocRingBuffer, RingBuffer, RingBufferExt, RingBufferWrite}; -//! -//! let mut buffer = AllocRingBuffer::with_capacity(2); -//! -//! // First entry of the buffer is now 5. -//! buffer.push(5); -//! -//! // The last item we pushed is 5 -//! assert_eq!(buffer.get(-1), Some(&5)); -//! -//! // Second entry is now 42. -//! buffer.push(42); -//! -//! assert_eq!(buffer.peek(), Some(&5)); -//! assert!(buffer.is_full()); -//! -//! // Because capacity is reached the next push will be the first item of the buffer. -//! buffer.push(1); -//! assert_eq!(buffer.to_vec(), vec![42, 1]); -//! -//! ``` -//! -//! # Features -//! -//! | name | default | description | -//! | --- | --- | --- | -//! | alloc | ✓ | Disable this feature to remove the dependency on alloc. Useful for kernels. | -//! -//! # License -//! -//! Licensed under the MIT License +#![doc = include_str!("../README.md")] #[cfg(feature = "alloc")] extern crate alloc; #[macro_use] pub(crate) mod ringbuffer_trait; -use core::usize; -pub use ringbuffer_trait::{RingBuffer, RingBufferExt, RingBufferRead, RingBufferWrite}; +pub use ringbuffer_trait::RingBuffer; #[cfg(feature = "alloc")] mod with_alloc; @@ -105,17 +54,15 @@ mod tests { use std::vec; use std::vec::Vec; - use crate::{ - AllocRingBuffer, ConstGenericRingBuffer, GrowableAllocRingBuffer, RingBuffer, - RingBufferExt, RingBufferRead, RingBufferWrite, - }; + use crate::ringbuffer_trait::{RingBufferIterator, RingBufferMutIterator}; + use crate::{AllocRingBuffer, ConstGenericRingBuffer, GrowableAllocRingBuffer, RingBuffer}; #[test] fn run_test_neg_index() { //! Test for issue #43 const capacity: usize = 8; - fn test_neg_index(mut b: impl RingBufferExt) { + fn test_neg_index(mut b: impl RingBuffer) { for i in 0..capacity + 2 { b.push(i); assert_eq!(b.get(-1), Some(&i)); @@ -165,7 +112,7 @@ mod tests { #[test] fn run_test_len() { - fn test_len(mut b: impl RingBufferWrite) { + fn test_len(mut b: impl RingBuffer) { assert_eq!(0, b.len()); b.push(1); assert_eq!(1, b.len()); @@ -180,7 +127,7 @@ mod tests { #[test] fn run_test_len_wrap() { - fn test_len_wrap(mut b: impl RingBufferWrite) { + fn test_len_wrap(mut b: impl RingBuffer) { assert_eq!(0, b.len()); b.push(1); assert_eq!(1, b.len()); @@ -209,7 +156,7 @@ mod tests { #[test] fn run_test_clear() { - fn test_clear(mut b: impl RingBufferExt) { + fn test_clear(mut b: impl RingBuffer) { b.push(1); b.push(2); b.push(3); @@ -226,7 +173,7 @@ mod tests { #[test] fn run_test_empty() { - fn test_empty(mut b: impl RingBufferExt) { + fn test_empty(mut b: impl RingBuffer) { assert!(b.is_empty()); b.push(1); b.push(2); @@ -245,7 +192,7 @@ mod tests { #[test] fn run_test_iter() { - fn test_iter(mut b: impl RingBufferExt) { + fn test_iter(mut b: impl RingBuffer) { b.push(1); b.push(2); b.push(3); @@ -270,9 +217,40 @@ mod tests { test_iter(ConstGenericRingBuffer::::new()); } + #[test] + fn run_test_iter_ref() { + fn test_iter(mut b: B) + where + B: RingBuffer, + for<'a> &'a B: IntoIterator>, + { + b.push(1); + b.push(2); + b.push(3); + b.push(4); + b.push(5); + b.push(6); + b.push(7); + + let mut iter = (&b).into_iter(); + assert_eq!(&1, iter.next().unwrap()); + assert_eq!(&7, iter.next_back().unwrap()); + assert_eq!(&2, iter.next().unwrap()); + assert_eq!(&3, iter.next().unwrap()); + assert_eq!(&6, iter.next_back().unwrap()); + assert_eq!(&5, iter.next_back().unwrap()); + assert_eq!(&4, iter.next().unwrap()); + assert_eq!(None, iter.next()); + } + + test_iter(AllocRingBuffer::new(8)); + test_iter(GrowableAllocRingBuffer::with_capacity(8)); + test_iter(ConstGenericRingBuffer::::new()); + } + #[test] fn run_test_into_iter() { - fn test_iter(mut b: impl RingBufferExt) { + fn test_iter(mut b: impl RingBuffer) { b.push(1); b.push(2); b.push(3); @@ -300,7 +278,7 @@ mod tests { #[cfg(feature = "alloc")] #[test] fn run_test_iter_with_lifetimes() { - fn test_iter<'a>(string: &'a str, mut b: impl RingBufferExt<&'a str>) { + fn test_iter<'a>(string: &'a str, mut b: impl RingBuffer<&'a str>) { b.push(&string[0..1]); b.push(&string[1..2]); b.push(&string[2..3]); @@ -322,7 +300,7 @@ mod tests { #[test] fn run_test_double_iter() { - fn test_double_iter(mut b: impl RingBufferExt) { + fn test_double_iter(mut b: impl RingBuffer) { b.push(1); b.push(2); b.push(3); @@ -345,7 +323,7 @@ mod tests { #[test] fn run_test_iter_wrap() { - fn test_iter_wrap(mut b: impl RingBufferExt) { + fn test_iter_wrap(mut b: impl RingBuffer) { b.push(1); b.push(2); // Wrap @@ -376,7 +354,7 @@ mod tests { #[test] fn run_test_iter_mut() { - fn test_iter_mut(mut b: impl RingBufferExt) { + fn test_iter_mut(mut b: impl RingBuffer) { b.push(1); b.push(2); b.push(3); @@ -393,9 +371,33 @@ mod tests { test_iter_mut(ConstGenericRingBuffer::::new()); } + #[test] + fn run_test_iter_mut_ref() { + fn test_iter_mut(mut b: B) + where + B: RingBuffer, + for<'a> &'a mut B: + IntoIterator>, + { + b.push(1); + b.push(2); + b.push(3); + + for el in &mut b { + *el += 1; + } + + assert_eq!(vec![2, 3, 4], b.to_vec()) + } + + test_iter_mut(AllocRingBuffer::new(8)); + test_iter_mut(GrowableAllocRingBuffer::with_capacity(8)); + test_iter_mut(ConstGenericRingBuffer::::new()); + } + #[test] fn test_iter_mut_wrap() { - fn run_test_iter_mut_wrap(mut b: impl RingBufferExt) { + fn run_test_iter_mut_wrap(mut b: impl RingBuffer) { b.push(1); b.push(2); b.push(3); @@ -426,7 +428,7 @@ mod tests { #[test] fn test_iter_mut_miri_fail() { - fn run_test_iter_mut_wrap(mut b: impl RingBufferExt) { + fn run_test_iter_mut_wrap(mut b: impl RingBuffer) { b.push(1); b.push(2); b.push(3); @@ -460,7 +462,7 @@ mod tests { #[test] fn run_test_to_vec() { - fn test_to_vec(mut b: impl RingBufferExt) { + fn test_to_vec(mut b: impl RingBuffer) { b.push(1); b.push(2); b.push(3); @@ -475,7 +477,7 @@ mod tests { #[test] fn run_test_to_vec_wrap() { - fn test_to_vec_wrap(mut b: impl RingBufferExt) { + fn test_to_vec_wrap(mut b: impl RingBuffer) { b.push(1); b.push(2); // Wrap @@ -499,7 +501,7 @@ mod tests { #[test] fn run_test_index() { - fn test_index(mut b: impl RingBufferExt) { + fn test_index(mut b: impl RingBuffer) { b.push(2); assert_eq!(b[0], 2) } @@ -511,7 +513,7 @@ mod tests { #[test] fn run_test_index_mut() { - fn test_index_mut(mut b: impl RingBufferExt) { + fn test_index_mut(mut b: impl RingBuffer) { b.push(2); assert_eq!(b[0], 2); @@ -528,7 +530,7 @@ mod tests { #[test] fn run_test_peek_some() { - fn test_peek_some(mut b: impl RingBufferExt) { + fn test_peek_some(mut b: impl RingBuffer) { b.push(1); b.push(2); @@ -542,7 +544,7 @@ mod tests { #[test] fn run_test_peek_none() { - fn test_peek_none(b: impl RingBufferExt) { + fn test_peek_none(b: impl RingBuffer) { assert_eq!(b.peek(), None); } @@ -553,7 +555,7 @@ mod tests { #[test] fn run_test_get_relative() { - fn test_get_relative(mut b: impl RingBufferExt) { + fn test_get_relative(mut b: impl RingBuffer) { b.push(0); b.push(1); @@ -578,7 +580,7 @@ mod tests { #[test] fn run_test_wrapping_get_relative() { - fn test_wrapping_get_relative(mut b: impl RingBufferExt) { + fn test_wrapping_get_relative(mut b: impl RingBuffer) { b.push(0); b.push(1); b.push(2); @@ -611,7 +613,7 @@ mod tests { #[test] fn run_test_get_relative_zero_length() { - fn test_get_relative_zero_length(b: impl RingBufferExt) { + fn test_get_relative_zero_length(b: impl RingBuffer) { assert!(b.get(1).is_none()); } @@ -622,7 +624,7 @@ mod tests { #[test] fn run_test_get_relative_mut() { - fn test_get_relative_mut(mut b: impl RingBufferExt) { + fn test_get_relative_mut(mut b: impl RingBuffer) { b.push(0); b.push(1); @@ -646,7 +648,7 @@ mod tests { #[test] fn run_test_wrapping_get_relative_mut() { - fn test_wrapping_get_relative_mut(mut b: impl RingBufferExt) { + fn test_wrapping_get_relative_mut(mut b: impl RingBuffer) { b.push(0); b.push(1); b.push(2); @@ -684,7 +686,7 @@ mod tests { #[test] fn run_test_get_relative_mut_zero_length() { - fn test_get_relative_mut_zero_length(mut b: impl RingBufferExt) { + fn test_get_relative_mut_zero_length(mut b: impl RingBuffer) { assert!(b.get_mut(1).is_none()); } @@ -696,7 +698,7 @@ mod tests { #[test] #[allow(deprecated)] fn run_test_get_absolute() { - fn test_get_absolute(mut b: impl RingBufferExt) { + fn test_get_absolute(mut b: impl RingBuffer) { b.push(0); b.push(1); @@ -717,7 +719,7 @@ mod tests { #[test] fn run_test_from_iterator() { - fn test_from_iterator + FromIterator>() { + fn test_from_iterator + FromIterator>() { let b: T = std::iter::repeat(1).take(1024).collect(); assert_eq!(b.len(), 1024); assert_eq!(b.to_vec(), vec![1; 1024]) @@ -729,7 +731,7 @@ mod tests { #[test] fn run_test_from_iterator_wrap() { - fn test_from_iterator_wrap + FromIterator>() { + fn test_from_iterator_wrap + FromIterator>() { let b: T = std::iter::repeat(1).take(8000).collect(); assert_eq!(b.len(), b.capacity()); assert_eq!(b.to_vec(), vec![1; b.capacity()]) @@ -741,7 +743,7 @@ mod tests { #[test] fn run_test_get_relative_negative() { - fn test_get_relative_negative(mut b: impl RingBufferExt) { + fn test_get_relative_negative(mut b: impl RingBuffer) { b.push(0); b.push(1); @@ -765,7 +767,7 @@ mod tests { #[test] fn run_test_contains() { - fn test_contains(mut b: impl RingBufferExt) { + fn test_contains(mut b: impl RingBuffer) { b.push(1); b.push(2); @@ -780,7 +782,7 @@ mod tests { #[test] fn run_test_is_full() { - fn test_is_full(mut b: impl RingBufferExt) { + fn test_is_full(mut b: impl RingBuffer) { assert!(!b.is_full()); b.push(1); assert!(!b.is_full()); @@ -795,7 +797,7 @@ mod tests { #[test] fn run_test_front_some() { - fn test_front_some(mut b: impl RingBufferExt) { + fn test_front_some(mut b: impl RingBuffer) { b.push(1); b.push(2); @@ -809,7 +811,7 @@ mod tests { #[test] fn run_test_front_none() { - fn test_front_none(b: impl RingBufferExt) { + fn test_front_none(b: impl RingBuffer) { assert_eq!(b.front(), None); } @@ -820,7 +822,7 @@ mod tests { #[test] fn run_test_back_some() { - fn test_back_some(mut b: impl RingBufferExt) { + fn test_back_some(mut b: impl RingBuffer) { b.push(1); b.push(2); @@ -834,7 +836,7 @@ mod tests { #[test] fn run_test_back_none() { - fn test_back_none(b: impl RingBufferExt) { + fn test_back_none(b: impl RingBuffer) { assert_eq!(b.back(), None); } @@ -845,7 +847,7 @@ mod tests { #[test] fn run_test_front_some_mut() { - fn test_front_some_mut(mut b: impl RingBufferExt) { + fn test_front_some_mut(mut b: impl RingBuffer) { b.push(1); b.push(2); @@ -859,7 +861,7 @@ mod tests { #[test] fn run_test_front_none_mut() { - fn test_front_none_mut(mut b: impl RingBufferExt) { + fn test_front_none_mut(mut b: impl RingBuffer) { assert_eq!(b.front_mut(), None); } @@ -870,7 +872,7 @@ mod tests { #[test] fn run_test_back_some_mut() { - fn test_back_some_mut(mut b: impl RingBufferExt) { + fn test_back_some_mut(mut b: impl RingBuffer) { b.push(1); b.push(2); @@ -884,7 +886,7 @@ mod tests { #[test] fn run_test_back_none_mut() { - fn test_back_none_mut(mut b: impl RingBufferExt) { + fn test_back_none_mut(mut b: impl RingBuffer) { assert_eq!(b.back_mut(), None); } @@ -895,7 +897,7 @@ mod tests { #[test] fn run_test_dequeue() { - fn run_test_dequeue(mut b: impl RingBufferExt) { + fn run_test_dequeue(mut b: impl RingBuffer) { b.push(0); b.push(1); @@ -916,7 +918,7 @@ mod tests { #[test] fn run_test_skip() { - fn test_skip(mut b: impl RingBufferExt) { + fn test_skip(mut b: impl RingBuffer) { b.push(0); b.push(1); @@ -935,7 +937,7 @@ mod tests { #[test] fn run_test_skip_2() { - fn test_skip2(mut rb: impl RingBufferExt) { + fn test_skip2(mut rb: impl RingBuffer) { rb.skip(); rb.skip(); rb.skip(); @@ -953,7 +955,7 @@ mod tests { #[test] fn run_test_push_dequeue_push() { - fn test_push_dequeue_push(mut b: impl RingBufferExt) { + fn test_push_dequeue_push(mut b: impl RingBuffer) { b.push(0); b.push(1); @@ -976,7 +978,7 @@ mod tests { #[test] fn run_test_enqueue_dequeue_push() { - fn test_enqueue_dequeue_push(mut b: impl RingBufferExt) { + fn test_enqueue_dequeue_push(mut b: impl RingBuffer) { b.enqueue(0); b.enqueue(1); @@ -999,7 +1001,7 @@ mod tests { #[test] fn large_negative_index() { - fn test_large_negative_index(mut b: impl RingBufferExt) { + fn test_large_negative_index(mut b: impl RingBuffer) { b.push(1); b.push(2); assert_eq!(b.get(1), Some(&2)); @@ -1016,7 +1018,7 @@ mod tests { #[test] fn large_negative_index_mut() { - fn test_large_negative_index(mut b: impl RingBufferExt) { + fn test_large_negative_index(mut b: impl RingBuffer) { b.push(1); b.push(2); assert_eq!(b.get_mut(1), Some(&mut 2)); @@ -1033,7 +1035,7 @@ mod tests { #[test] fn run_test_push_dequeue_push_full() { - fn test_push_dequeue_push_full(mut b: impl RingBufferExt) { + fn test_push_dequeue_push_full(mut b: impl RingBuffer) { b.push(0); b.push(1); b.push(2); @@ -1077,7 +1079,7 @@ mod tests { #[test] fn run_test_push_dequeue_push_full_get() { - fn test_push_dequeue_push_full_get(mut b: impl RingBufferExt) { + fn test_push_dequeue_push_full_get(mut b: impl RingBuffer) { b.push(0); b.push(1); b.push(2); @@ -1140,7 +1142,7 @@ mod tests { #[cfg_attr(miri, ignore)] // this test takes far too long with Miri enabled fn run_test_push_dequeue_push_full_get_rep() { - fn test_push_dequeue_push_full_get_rep(mut rb: impl RingBufferExt) { + fn test_push_dequeue_push_full_get_rep(mut rb: impl RingBuffer) { for _ in 0..100_000 { rb.push(1); rb.push(2); @@ -1169,7 +1171,7 @@ mod tests { #[test] fn run_test_clone() { - fn test_clone(mut rb: impl RingBufferExt + Clone + Eq + Debug) { + fn test_clone(mut rb: impl RingBuffer + Clone + Eq + Debug) { rb.push(42); rb.push(32); rb.push(22); @@ -1193,7 +1195,7 @@ mod tests { #[test] fn run_test_default_fill() { - fn test_default_fill(mut rb: impl RingBufferExt) { + fn test_default_fill(mut rb: impl RingBuffer) { for i in 0..rb.capacity() { for _ in 0..i { rb.push(1); @@ -1233,7 +1235,7 @@ mod tests { #[test] fn run_next_back_test() { - fn next_back_test(mut rb: impl RingBufferExt) { + fn next_back_test(mut rb: impl RingBuffer) { for i in 1..=4 { rb.push(i); } @@ -1253,7 +1255,7 @@ mod tests { #[test] fn run_next_back_test_mut() { - fn next_back_test_mut(mut rb: impl RingBufferExt) { + fn next_back_test_mut(mut rb: impl RingBuffer) { for i in 1..=4 { rb.push(i); } @@ -1272,7 +1274,7 @@ mod tests { } #[test] fn run_test_fill() { - fn test_fill(mut rb: impl RingBufferExt) { + fn test_fill(mut rb: impl RingBuffer) { for i in 0..rb.capacity() { for _ in 0..i { rb.push(1); diff --git a/src/ringbuffer_trait.rs b/src/ringbuffer_trait.rs index 341247d..21f255a 100644 --- a/src/ringbuffer_trait.rs +++ b/src/ringbuffer_trait.rs @@ -11,8 +11,16 @@ use alloc::vec::Vec; /// This trait is not object safe, so can't be used dynamically. However it is possible to /// define a generic function over types implementing `RingBuffer`. /// -/// Most actual functionality of ringbuffers is contained in the extension traits [`RingBufferExt`], [`RingBufferRead`] and [`RingBufferWrite`] -pub trait RingBuffer: Sized { +/// # Safety +/// Implementing this implies that the ringbuffer upholds some safety +/// guarantees, such as returning a different value from `get_mut` any +/// for every different index passed in. See the exact requirements +/// in the safety comment on the next function of the mutable Iterator +/// implementation, since these safety guarantees are necessary for +/// [`iter_mut`](RingBuffer::iter_mut) to work +pub unsafe trait RingBuffer: + Sized + IntoIterator + Extend + Index + IndexMut +{ /// Returns the length of the internal buffer. /// This length grows up to the capacity and then stops growing. /// This is because when the length is reached, new items are appended at the start. @@ -49,23 +57,15 @@ pub trait RingBuffer: Sized { /// Safety: ONLY SAFE WHEN self is a *mut to to an implementor of RingBuffer #[doc(hidden)] unsafe fn ptr_capacity(rb: *const Self) -> usize; -} -/// Defines behaviour for ringbuffers which allow for writing to the end of them (as a queue). -/// For arbitrary buffer access however, [`RingBufferExt`] is necessary. -pub trait RingBufferWrite: RingBuffer + Extend { /// Pushes a value onto the buffer. Cycles around if capacity is reached. fn push(&mut self, value: T); - /// alias for [`push`](RingBufferWrite::push), forming a more natural counterpart to [`dequeue`](RingBufferRead::dequeue) + /// alias for [`push`](RingBuffer::push), forming a more natural counterpart to [`dequeue`](RingBuffer::dequeue) fn enqueue(&mut self, value: T) { self.push(value); } -} -/// Defines behaviour for ringbuffers which allow for reading from the start of them (as a queue). -/// For arbitrary buffer access however, [`RingBufferExt`] is necessary. -pub trait RingBufferRead: RingBuffer + IntoIterator { /// dequeues the top item off the ringbuffer, and moves this item out. fn dequeue(&mut self) -> Option; @@ -77,9 +77,9 @@ pub trait RingBufferRead: RingBuffer + IntoIterator { /// dequeueing elements as they are iterated over. /// /// ``` - /// use ringbuffer::{AllocRingBuffer, RingBufferWrite, RingBufferRead, RingBuffer}; + /// use ringbuffer::{AllocRingBuffer, RingBuffer}; /// - /// let mut rb = AllocRingBuffer::with_capacity(16); + /// let mut rb = AllocRingBuffer::new(16); /// for i in 0..8 { /// rb.push(i); /// } @@ -98,21 +98,7 @@ pub trait RingBufferRead: RingBuffer + IntoIterator { fn drain(&mut self) -> RingBufferDrainingIterator { RingBufferDrainingIterator::new(self) } -} -/// Defines behaviour for ringbuffers which allow them to be used as a general purpose buffer. -/// With this trait, arbitrary access of elements in the buffer is possible. -/// -/// # Safety -/// Implementing this implies that the ringbuffer upholds some safety -/// guarantees, such as returning a different value from `get_mut` any -/// for every different index passed in. See the exact requirements -/// in the safety comment on the next function of the mutable Iterator -/// implementation, since these safety guarantees are necessary for -/// [`iter_mut`](RingBufferExt::iter_mut) to work -pub unsafe trait RingBufferExt: - RingBuffer + RingBufferRead + RingBufferWrite + Index + IndexMut -{ /// Sets every element in the ringbuffer to the value returned by f. fn fill_with T>(&mut self, f: F); @@ -147,8 +133,8 @@ pub unsafe trait RingBufferExt: unsafe { Self::ptr_get_mut(self, index).map(|i| &mut *i) } } - /// same as [`get_mut`](RingBufferExt::get_mut) but on raw pointers. - /// Safety: ONLY SAFE WHEN self is a *mut to to an implementor of RingBufferExt + /// same as [`get_mut`](RingBuffer::get_mut) but on raw pointers. + /// Safety: ONLY SAFE WHEN self is a *mut to to an implementor of RingBuffer #[doc(hidden)] unsafe fn ptr_get_mut(rb: *mut Self, index: isize) -> Option<*mut T>; @@ -232,21 +218,21 @@ pub unsafe trait RingBufferExt: } mod iter { - use crate::{RingBufferExt, RingBufferRead}; + use crate::RingBuffer; use core::iter::FusedIterator; use core::marker::PhantomData; use core::ptr::NonNull; - /// `RingBufferIterator` holds a reference to a `RingBufferExt` and iterates over it. `index` is the + /// `RingBufferIterator` holds a reference to a `RingBuffer` and iterates over it. `index` is the /// current iterator position. - pub struct RingBufferIterator<'rb, T, RB: RingBufferExt> { + pub struct RingBufferIterator<'rb, T, RB: RingBuffer> { obj: &'rb RB, len: usize, index: usize, phantom: PhantomData, } - impl<'rb, T, RB: RingBufferExt> RingBufferIterator<'rb, T, RB> { + impl<'rb, T, RB: RingBuffer> RingBufferIterator<'rb, T, RB> { #[inline] pub fn new(obj: &'rb RB) -> Self { Self { @@ -258,7 +244,7 @@ mod iter { } } - impl<'rb, T: 'rb, RB: RingBufferExt> Iterator for RingBufferIterator<'rb, T, RB> { + impl<'rb, T: 'rb, RB: RingBuffer> Iterator for RingBufferIterator<'rb, T, RB> { type Item = &'rb T; #[inline] @@ -277,11 +263,11 @@ mod iter { } } - impl<'rb, T: 'rb, RB: RingBufferExt> FusedIterator for RingBufferIterator<'rb, T, RB> {} + impl<'rb, T: 'rb, RB: RingBuffer> FusedIterator for RingBufferIterator<'rb, T, RB> {} - impl<'rb, T: 'rb, RB: RingBufferExt> ExactSizeIterator for RingBufferIterator<'rb, T, RB> {} + impl<'rb, T: 'rb, RB: RingBuffer> ExactSizeIterator for RingBufferIterator<'rb, T, RB> {} - impl<'rb, T: 'rb, RB: RingBufferExt> DoubleEndedIterator for RingBufferIterator<'rb, T, RB> { + impl<'rb, T: 'rb, RB: RingBuffer> DoubleEndedIterator for RingBufferIterator<'rb, T, RB> { #[inline] fn next_back(&mut self) -> Option { if self.len > 0 && self.index < self.len { @@ -294,19 +280,19 @@ mod iter { } } - /// `RingBufferMutIterator` holds a reference to a `RingBufferExt` and iterates over it. `index` is the + /// `RingBufferMutIterator` holds a reference to a `RingBuffer` and iterates over it. `index` is the /// current iterator position. /// /// WARNING: NEVER ACCESS THE `obj` FIELD OUTSIDE OF NEXT. It's private on purpose, and /// can technically be accessed in the same module. However, this breaks the safety of `next()` - pub struct RingBufferMutIterator<'rb, T, RB: RingBufferExt> { + pub struct RingBufferMutIterator<'rb, T, RB: RingBuffer> { obj: NonNull, index: usize, len: usize, phantom: PhantomData<&'rb mut T>, } - impl<'rb, T, RB: RingBufferExt> RingBufferMutIterator<'rb, T, RB> { + impl<'rb, T, RB: RingBuffer> RingBufferMutIterator<'rb, T, RB> { pub fn new(obj: &'rb mut RB) -> Self { Self { len: obj.len(), @@ -317,14 +303,11 @@ mod iter { } } - impl<'rb, T: 'rb, RB: RingBufferExt + 'rb> FusedIterator for RingBufferMutIterator<'rb, T, RB> {} + impl<'rb, T: 'rb, RB: RingBuffer + 'rb> FusedIterator for RingBufferMutIterator<'rb, T, RB> {} - impl<'rb, T: 'rb, RB: RingBufferExt + 'rb> ExactSizeIterator - for RingBufferMutIterator<'rb, T, RB> - { - } + impl<'rb, T: 'rb, RB: RingBuffer + 'rb> ExactSizeIterator for RingBufferMutIterator<'rb, T, RB> {} - impl<'rb, T: 'rb, RB: RingBufferExt + 'rb> DoubleEndedIterator + impl<'rb, T: 'rb, RB: RingBuffer + 'rb> DoubleEndedIterator for RingBufferMutIterator<'rb, T, RB> { #[inline] @@ -339,7 +322,7 @@ mod iter { } } - impl<'rb, T, RB: RingBufferExt + 'rb> Iterator for RingBufferMutIterator<'rb, T, RB> { + impl<'rb, T, RB: RingBuffer + 'rb> Iterator for RingBufferMutIterator<'rb, T, RB> { type Item = &'rb mut T; fn next(&mut self) -> Option { @@ -358,13 +341,13 @@ mod iter { } } - /// `RingBufferMutIterator` holds a reference to a `RingBufferRead` and iterates over it. - pub struct RingBufferDrainingIterator<'rb, T, RB: RingBufferRead> { + /// `RingBufferMutIterator` holds a reference to a `RingBuffer` and iterates over it. + pub struct RingBufferDrainingIterator<'rb, T, RB: RingBuffer> { obj: &'rb mut RB, phantom: PhantomData, } - impl<'rb, T, RB: RingBufferRead> RingBufferDrainingIterator<'rb, T, RB> { + impl<'rb, T, RB: RingBuffer> RingBufferDrainingIterator<'rb, T, RB> { #[inline] pub fn new(obj: &'rb mut RB) -> Self { Self { @@ -374,7 +357,7 @@ mod iter { } } - impl<'rb, T, RB: RingBufferRead> Iterator for RingBufferDrainingIterator<'rb, T, RB> { + impl<'rb, T, RB: RingBuffer> Iterator for RingBufferDrainingIterator<'rb, T, RB> { type Item = T; fn next(&mut self) -> Option { @@ -386,13 +369,13 @@ mod iter { } } - /// `RingBufferIntoIterator` holds a `RingBufferRead` and iterates over it. - pub struct RingBufferIntoIterator> { + /// `RingBufferIntoIterator` holds a `RingBuffer` and iterates over it. + pub struct RingBufferIntoIterator> { obj: RB, phantom: PhantomData, } - impl> RingBufferIntoIterator { + impl> RingBufferIntoIterator { #[inline] pub fn new(obj: RB) -> Self { Self { @@ -402,7 +385,7 @@ mod iter { } } - impl> Iterator for RingBufferIntoIterator { + impl> Iterator for RingBufferIntoIterator { type Item = T; #[inline] @@ -420,7 +403,7 @@ pub use iter::{ RingBufferDrainingIterator, RingBufferIntoIterator, RingBufferIterator, RingBufferMutIterator, }; -/// Implement various functions on implementors of [`RingBufferRead`]. +/// Implement various functions on implementors of [`RingBuffer`]. /// This is to avoid duplicate code. macro_rules! impl_ringbuffer_read { () => { @@ -442,7 +425,7 @@ macro_rules! impl_ringbuffer { }; } -/// Implement various functions on implementors of [`RingBufferExt`]. +/// Implement various functions on implementors of [`RingBuffer`]. /// This is to avoid duplicate code. macro_rules! impl_ringbuffer_ext { ($get_unchecked: ident, $get_unchecked_mut: ident, $readptr: ident, $writeptr: ident, $mask: expr) => { diff --git a/src/with_alloc/alloc_ringbuffer.rs b/src/with_alloc/alloc_ringbuffer.rs index 5929b7b..06b237c 100644 --- a/src/with_alloc/alloc_ringbuffer.rs +++ b/src/with_alloc/alloc_ringbuffer.rs @@ -1,7 +1,7 @@ use core::ops::{Index, IndexMut}; use crate::ringbuffer_trait::{ - RingBuffer, RingBufferExt, RingBufferIntoIterator, RingBufferRead, RingBufferWrite, + RingBuffer, RingBufferIntoIterator, RingBufferIterator, RingBufferMutIterator, }; extern crate alloc; @@ -61,15 +61,15 @@ impl RingbufferSize for NonPowerOfTwo { } } -/// The `AllocRingBuffer` is a `RingBufferExt` which is based on a Vec. This means it allocates at runtime +/// The `AllocRingBuffer` is a `RingBuffer` which is based on a Vec. This means it allocates at runtime /// on the heap, and therefore needs the [`alloc`] crate. This struct and therefore the dependency on /// alloc can be disabled by disabling the `alloc` (default) feature. /// /// # Example /// ``` -/// use ringbuffer::{AllocRingBuffer, RingBuffer, RingBufferExt, RingBufferWrite}; +/// use ringbuffer::{AllocRingBuffer, RingBuffer}; /// -/// let mut buffer = AllocRingBuffer::with_capacity(2); +/// let mut buffer = AllocRingBuffer::new(2); /// /// // First entry of the buffer is now 5. /// buffer.push(5); @@ -224,28 +224,6 @@ impl PartialEq for AllocRingBuffer impl Eq for AllocRingBuffer {} -unsafe impl RingBufferExt for AllocRingBuffer { - impl_ringbuffer_ext!( - get_unchecked, - get_unchecked_mut, - readptr, - writeptr, - SIZE::mask - ); - - #[inline] - fn fill_with T>(&mut self, mut f: F) { - self.clear(); - - self.readptr = 0; - self.writeptr = self.capacity; - - for i in 0..self.capacity { - unsafe { ptr::write(get_unchecked_mut(self, i), f()) }; - } - } -} - impl IntoIterator for AllocRingBuffer { type Item = T; type IntoIter = RingBufferIntoIterator; @@ -255,23 +233,22 @@ impl IntoIterator for AllocRingBuffer { } } -impl RingBufferRead for AllocRingBuffer { - fn dequeue(&mut self) -> Option { - if self.is_empty() { - None - } else { - let index = SIZE::mask(self.capacity, self.readptr); - let res = unsafe { get_unchecked_mut(self, index) }; - self.readptr += 1; +impl<'a, T, SIZE: RingbufferSize> IntoIterator for &'a AllocRingBuffer { + type Item = &'a T; + type IntoIter = RingBufferIterator<'a, T, AllocRingBuffer>; - // Safety: the fact that we got this maybeuninit from the buffer (with mask) means that - // it's initialized. If it wasn't the is_empty call would have caught it. Values - // are always initialized when inserted so this is safe. - unsafe { Some(ptr::read(res)) } - } + fn into_iter(self) -> Self::IntoIter { + self.iter() } +} - impl_ringbuffer_read!(); +impl<'a, T, SIZE: RingbufferSize> IntoIterator for &'a mut AllocRingBuffer { + type Item = &'a mut T; + type IntoIter = RingBufferMutIterator<'a, T, AllocRingBuffer>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } } impl Extend for AllocRingBuffer { @@ -284,7 +261,14 @@ impl Extend for AllocRingBuffer { } } -impl RingBufferWrite for AllocRingBuffer { +unsafe impl RingBuffer for AllocRingBuffer { + #[inline] + unsafe fn ptr_capacity(rb: *const Self) -> usize { + (*rb).capacity + } + + impl_ringbuffer!(readptr, writeptr); + #[inline] fn push(&mut self, value: T) { if self.is_full() { @@ -314,15 +298,43 @@ impl RingBufferWrite for AllocRingBuffer { self.writeptr += 1; } -} -impl RingBuffer for AllocRingBuffer { - #[inline] - unsafe fn ptr_capacity(rb: *const Self) -> usize { - (*rb).capacity + impl_ringbuffer_read!(); + + fn dequeue(&mut self) -> Option { + if self.is_empty() { + None + } else { + let index = SIZE::mask(self.capacity, self.readptr); + let res = unsafe { get_unchecked_mut(self, index) }; + self.readptr += 1; + + // Safety: the fact that we got this maybeuninit from the buffer (with mask) means that + // it's initialized. If it wasn't the is_empty call would have caught it. Values + // are always initialized when inserted so this is safe. + unsafe { Some(ptr::read(res)) } + } } - impl_ringbuffer!(readptr, writeptr); + impl_ringbuffer_ext!( + get_unchecked, + get_unchecked_mut, + readptr, + writeptr, + SIZE::mask + ); + + #[inline] + fn fill_with T>(&mut self, mut f: F) { + self.clear(); + + self.readptr = 0; + self.writeptr = self.capacity; + + for i in 0..self.capacity { + unsafe { ptr::write(get_unchecked_mut(self, i), f()) }; + } + } } impl AllocRingBuffer { @@ -446,7 +458,7 @@ impl IndexMut for AllocRingBuffer { #[cfg(test)] mod tests { use crate::with_alloc::alloc_ringbuffer::RingbufferSize; - use crate::{AllocRingBuffer, RingBuffer, RingBufferExt, RingBufferRead, RingBufferWrite}; + use crate::{AllocRingBuffer, RingBuffer}; // just test that this compiles #[test] diff --git a/src/with_alloc/vecdeque.rs b/src/with_alloc/vecdeque.rs index fcdea6a..c82d8fb 100644 --- a/src/with_alloc/vecdeque.rs +++ b/src/with_alloc/vecdeque.rs @@ -1,6 +1,6 @@ -use crate::ringbuffer_trait::RingBufferIntoIterator; +use crate::ringbuffer_trait::{RingBufferIntoIterator, RingBufferIterator, RingBufferMutIterator}; use crate::with_alloc::alloc_ringbuffer::RingbufferSize; -use crate::{AllocRingBuffer, RingBuffer, RingBufferExt, RingBufferRead, RingBufferWrite}; +use crate::{AllocRingBuffer, RingBuffer}; use alloc::collections::VecDeque; use core::ops::{Deref, DerefMut, Index, IndexMut}; @@ -142,16 +142,6 @@ impl GrowableAllocRingBuffer { } } -impl RingBuffer for GrowableAllocRingBuffer { - unsafe fn ptr_len(rb: *const Self) -> usize { - (*rb).0.len() - } - - unsafe fn ptr_capacity(rb: *const Self) -> usize { - (*rb).0.capacity() - } -} - impl IntoIterator for GrowableAllocRingBuffer { type Item = T; type IntoIter = RingBufferIntoIterator; @@ -161,47 +151,43 @@ impl IntoIterator for GrowableAllocRingBuffer { } } -impl RingBufferRead for GrowableAllocRingBuffer { - fn dequeue(&mut self) -> Option { - self.pop_front() - } - - impl_ringbuffer_read!(); -} +impl<'a, T> IntoIterator for &'a GrowableAllocRingBuffer { + type Item = &'a T; + type IntoIter = RingBufferIterator<'a, T, GrowableAllocRingBuffer>; -impl RingBufferWrite for GrowableAllocRingBuffer { - fn push(&mut self, value: T) { - self.push_back(value); + fn into_iter(self) -> Self::IntoIter { + self.iter() } } -impl Extend for GrowableAllocRingBuffer { - fn extend>(&mut self, iter: I) { - self.0.extend(iter); +impl<'a, T> IntoIterator for &'a mut GrowableAllocRingBuffer { + type Item = &'a mut T; + type IntoIter = RingBufferMutIterator<'a, T, GrowableAllocRingBuffer>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() } } -impl Index for GrowableAllocRingBuffer { - type Output = T; +unsafe impl RingBuffer for GrowableAllocRingBuffer { + unsafe fn ptr_len(rb: *const Self) -> usize { + (*rb).0.len() + } - fn index(&self, index: isize) -> &Self::Output { - self.get(index).expect("index out of bounds") + unsafe fn ptr_capacity(rb: *const Self) -> usize { + (*rb).0.capacity() } -} -impl IndexMut for GrowableAllocRingBuffer { - fn index_mut(&mut self, index: isize) -> &mut Self::Output { - self.get_mut(index).expect("index out of bounds") + fn dequeue(&mut self) -> Option { + self.pop_front() } -} -impl FromIterator for GrowableAllocRingBuffer { - fn from_iter>(iter: I) -> Self { - Self(VecDeque::from_iter(iter)) + impl_ringbuffer_read!(); + + fn push(&mut self, value: T) { + self.push_back(value); } -} -unsafe impl RingBufferExt for GrowableAllocRingBuffer { fn fill_with T>(&mut self, mut f: F) { self.clear(); let initial_capacity = self.0.capacity(); @@ -256,3 +242,29 @@ unsafe impl RingBufferExt for GrowableAllocRingBuffer { unimplemented!() } } + +impl Extend for GrowableAllocRingBuffer { + fn extend>(&mut self, iter: I) { + self.0.extend(iter); + } +} + +impl Index for GrowableAllocRingBuffer { + type Output = T; + + fn index(&self, index: isize) -> &Self::Output { + self.get(index).expect("index out of bounds") + } +} + +impl IndexMut for GrowableAllocRingBuffer { + fn index_mut(&mut self, index: isize) -> &mut Self::Output { + self.get_mut(index).expect("index out of bounds") + } +} + +impl FromIterator for GrowableAllocRingBuffer { + fn from_iter>(iter: I) -> Self { + Self(VecDeque::from_iter(iter)) + } +} diff --git a/src/with_const_generics.rs b/src/with_const_generics.rs index 56e6cf8..7fba0c3 100644 --- a/src/with_const_generics.rs +++ b/src/with_const_generics.rs @@ -1,6 +1,6 @@ -use crate::ringbuffer_trait::RingBufferIntoIterator; +use crate::ringbuffer_trait::{RingBufferIntoIterator, RingBufferIterator, RingBufferMutIterator}; use crate::with_alloc::alloc_ringbuffer::RingbufferSize; -use crate::{RingBuffer, RingBufferExt, RingBufferRead, RingBufferWrite}; +use crate::RingBuffer; use core::iter::FromIterator; use core::mem; use core::mem::MaybeUninit; @@ -14,7 +14,7 @@ use core::ops::{Index, IndexMut}; /// /// # Example /// ``` -/// use ringbuffer::{ConstGenericRingBuffer, RingBuffer, RingBufferExt, RingBufferWrite}; +/// use ringbuffer::{ConstGenericRingBuffer, RingBuffer}; /// /// let mut buffer = ConstGenericRingBuffer::<_, 2>::new(); /// @@ -223,23 +223,22 @@ impl IntoIterator for ConstGenericRingBuffer { } } -impl RingBufferRead for ConstGenericRingBuffer { - fn dequeue(&mut self) -> Option { - if self.is_empty() { - None - } else { - let index = crate::mask_modulo(CAP, self.readptr); - let res = mem::replace(&mut self.buf[index], MaybeUninit::uninit()); - self.readptr += 1; +impl<'a, T, const CAP: usize> IntoIterator for &'a ConstGenericRingBuffer { + type Item = &'a T; + type IntoIter = RingBufferIterator<'a, T, ConstGenericRingBuffer>; - // Safety: the fact that we got this maybeuninit from the buffer (with mask) means that - // it's initialized. If it wasn't the is_empty call would have caught it. Values - // are always initialized when inserted so this is safe. - unsafe { Some(res.assume_init()) } - } + fn into_iter(self) -> Self::IntoIter { + self.iter() } +} - impl_ringbuffer_read!(); +impl<'a, T, const CAP: usize> IntoIterator for &'a mut ConstGenericRingBuffer { + type Item = &'a mut T; + type IntoIter = RingBufferMutIterator<'a, T, ConstGenericRingBuffer>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } } impl Extend for ConstGenericRingBuffer { @@ -252,7 +251,15 @@ impl Extend for ConstGenericRingBuffer { } } -impl RingBufferWrite for ConstGenericRingBuffer { +unsafe impl RingBuffer for ConstGenericRingBuffer { + #[inline] + #[cfg(not(tarpaulin_include))] + unsafe fn ptr_capacity(_: *const Self) -> usize { + CAP + } + + impl_ringbuffer!(readptr, writeptr); + #[inline] fn push(&mut self, value: T) { if self.is_full() { @@ -273,9 +280,24 @@ impl RingBufferWrite for ConstGenericRingBuffer self.buf[index] = MaybeUninit::new(value); self.writeptr += 1; } -} -unsafe impl RingBufferExt for ConstGenericRingBuffer { + impl_ringbuffer_read!(); + + fn dequeue(&mut self) -> Option { + if self.is_empty() { + None + } else { + let index = crate::mask_modulo(CAP, self.readptr); + let res = mem::replace(&mut self.buf[index], MaybeUninit::uninit()); + self.readptr += 1; + + // Safety: the fact that we got this maybeuninit from the buffer (with mask) means that + // it's initialized. If it wasn't the is_empty call would have caught it. Values + // are always initialized when inserted so this is safe. + unsafe { Some(res.assume_init()) } + } + } + impl_ringbuffer_ext!( get_unchecked, get_unchecked_mut, @@ -293,16 +315,6 @@ unsafe impl RingBufferExt for ConstGenericRingBuffer RingBuffer for ConstGenericRingBuffer { - #[inline] - #[cfg(not(tarpaulin_include))] - unsafe fn ptr_capacity(_: *const Self) -> usize { - CAP - } - - impl_ringbuffer!(readptr, writeptr); -} - impl Default for ConstGenericRingBuffer { /// Creates a buffer with a capacity specified through the Cap type parameter. /// # Panics diff --git a/tests/conversions.rs b/tests/conversions.rs index 8140f40..5816a5e 100644 --- a/tests/conversions.rs +++ b/tests/conversions.rs @@ -3,8 +3,8 @@ extern crate alloc; use alloc::collections::{LinkedList, VecDeque}; use alloc::string::ToString; use core::ops::Deref; +use ringbuffer::RingBuffer; use ringbuffer::{AllocRingBuffer, ConstGenericRingBuffer, GrowableAllocRingBuffer}; -use ringbuffer::{RingBufferExt, RingBufferWrite}; use std::vec; macro_rules! convert_test {