diff --git a/README.md b/README.md index 2c438e1..e3cd9ae 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ fn main() { buffer.push(5); // The last item we pushed is 5 - assert_eq!(buffer.get(-1), Some(&5)); + assert_eq!(buffer.back(), Some(&5)); // Second entry is now 42. buffer.push(42); diff --git a/benches/bench.rs b/benches/bench.rs index 1b13b85..6793a40 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,3 +1,4 @@ +#![no_coverage] use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion}; use ringbuffer::{AllocRingBuffer, ConstGenericRingBuffer, RingBuffer}; @@ -40,8 +41,8 @@ fn benchmark_push_dequeue, F: Fn() -> T>(b: &mut Bencher, new rb.push(2); black_box(()); - assert_eq!(black_box(rb.get(-1)), Some(&2)); - assert_eq!(black_box(rb.get(-2)), Some(&1)); + assert_eq!(black_box(rb.get_signed(-1)), Some(&2)); + assert_eq!(black_box(rb.get_signed(-2)), Some(&1)); } rb @@ -55,7 +56,7 @@ fn benchmark_various, F: Fn() -> T>(b: &mut Bencher, new: F) for i in 0..100_000 { rb.push(i); black_box(()); - black_box(rb.get(-1)); + black_box(rb.back()); } rb diff --git a/src/lib.rs b/src/lib.rs index d115bde..fa3dd17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,9 @@ pub use with_const_generics::ConstGenericRingBuffer; /// Used internally. Computes the bitmask used to properly wrap the ringbuffers. #[inline] -const fn mask(cap: usize, index: usize) -> usize { +#[cfg(feature = "alloc")] +const fn mask_and(cap: usize, index: usize) -> usize { + debug_assert!(cap.is_power_of_two()); index & (cap - 1) } @@ -63,7 +65,7 @@ mod tests { fn test_neg_index(mut b: impl RingBuffer) { for i in 0..capacity + 2 { b.push(i); - assert_eq!(b.get(-1), Some(&i)); + assert_eq!(b.get_signed(-1), Some(&i)); } } @@ -215,6 +217,60 @@ mod tests { test_iter(ConstGenericRingBuffer::::new()); } + #[test] + fn run_test_forward_iter_non_power_of_two() { + fn test_iter(mut b: impl RingBuffer) { + 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.iter(); + assert_eq!(&1, iter.next().unwrap()); + assert_eq!(&2, iter.next().unwrap()); + assert_eq!(&3, iter.next().unwrap()); + assert_eq!(&4, iter.next().unwrap()); + assert_eq!(&5, iter.next().unwrap()); + assert_eq!(&6, iter.next().unwrap()); + assert_eq!(&7, iter.next().unwrap()); + assert_eq!(None, iter.next()); + } + + test_iter(AllocRingBuffer::new(7)); + test_iter(GrowableAllocRingBuffer::with_capacity(7)); + test_iter(ConstGenericRingBuffer::::new()); + } + + #[test] + fn run_test_iter_non_power_of_two() { + fn test_iter(mut b: impl RingBuffer) { + 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.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(7)); + test_iter(GrowableAllocRingBuffer::with_capacity(7)); + test_iter(ConstGenericRingBuffer::::new()); + } + #[test] fn run_test_iter_ref() { fn test_iter(mut b: B) @@ -509,6 +565,33 @@ mod tests { test_index(ConstGenericRingBuffer::::new()); } + #[test] + fn run_test_get() { + fn test_index(mut b: impl RingBuffer) { + b.push(0); + b.push(1); + b.push(2); + b.push(3); + b.push(4); + b.push(5); + b.push(6); + b.push(7); + + assert_eq!(b.get(0), Some(&0)); + assert_eq!(b.get(1), Some(&1)); + assert_eq!(b.get(2), Some(&2)); + assert_eq!(b.get(3), Some(&3)); + assert_eq!(b.get(4), Some(&4)); + assert_eq!(b.get(5), Some(&5)); + assert_eq!(b.get(6), Some(&6)); + assert_eq!(b.get(7), Some(&7)); + } + + test_index(AllocRingBuffer::new(8)); + test_index(GrowableAllocRingBuffer::with_capacity(8)); + test_index(ConstGenericRingBuffer::::new()); + } + #[test] fn run_test_index_mut() { fn test_index_mut(mut b: impl RingBuffer) { @@ -557,11 +640,6 @@ mod tests { b.push(0); b.push(1); - // [0, ...] - // ^ - // [0, 1, ...] - // ^ - // get[(index + 0) % len] = 0 (wrap to 0 because len == 2) // get[(index + 1) % len] = 1 assert_eq!(b.get(0).unwrap(), &0); assert_eq!(b.get(1).unwrap(), &1); @@ -729,12 +807,12 @@ mod tests { // ^ // get[(index + -1) % len] = 1 // get[(index + -2) % len] = 0 (wrap to 1 because len == 2) - assert_eq!(b.get(-1).unwrap(), &1); - assert_eq!(b.get(-2).unwrap(), &0); + assert_eq!(b.get_signed(-1).unwrap(), &1); + assert_eq!(b.get_signed(-2).unwrap(), &0); // Wraps around - assert_eq!(b.get(-3).unwrap(), &1); - assert_eq!(b.get(-4).unwrap(), &0); + assert_eq!(b.get_signed(-3).unwrap(), &1); + assert_eq!(b.get_signed(-4).unwrap(), &0); } test_get_relative_negative(AllocRingBuffer::new(8)); @@ -980,11 +1058,11 @@ mod tests { fn test_large_negative_index(mut b: impl RingBuffer) { b.push(1); b.push(2); - assert_eq!(b.get(1), Some(&2)); - assert_eq!(b.get(0), Some(&1)); - assert_eq!(b.get(-1), Some(&2)); - assert_eq!(b.get(-2), Some(&1)); - assert_eq!(b.get(-3), Some(&2)); + assert_eq!(b.get_signed(1), Some(&2)); + assert_eq!(b.get_signed(0), Some(&1)); + assert_eq!(b.get_signed(-1), Some(&2)); + assert_eq!(b.get_signed(-2), Some(&1)); + assert_eq!(b.get_signed(-3), Some(&2)); } test_large_negative_index(AllocRingBuffer::new(2)); @@ -997,11 +1075,11 @@ mod tests { fn test_large_negative_index(mut b: impl RingBuffer) { b.push(1); b.push(2); - assert_eq!(b.get_mut(1), Some(&mut 2)); - assert_eq!(b.get_mut(0), Some(&mut 1)); - assert_eq!(b.get_mut(-1), Some(&mut 2)); - assert_eq!(b.get_mut(-2), Some(&mut 1)); - assert_eq!(b.get_mut(-3), Some(&mut 2)); + assert_eq!(b.get_mut_signed(1), Some(&mut 2)); + assert_eq!(b.get_mut_signed(0), Some(&mut 1)); + assert_eq!(b.get_mut_signed(-1), Some(&mut 2)); + assert_eq!(b.get_mut_signed(-2), Some(&mut 1)); + assert_eq!(b.get_mut_signed(-3), Some(&mut 2)); } test_large_negative_index(AllocRingBuffer::new(2)); @@ -1076,9 +1154,9 @@ mod tests { b.push(1); b.push(2); - assert_eq!(b.get(-1), Some(&2)); - assert_eq!(b.get(-2), Some(&1)); - assert_eq!(b.get(-3), Some(&2)); + assert_eq!(b.get_signed(-1), Some(&2)); + assert_eq!(b.get_signed(-2), Some(&1)); + assert_eq!(b.get_signed(-3), Some(&2)); } test_push_dequeue_push_full_get(AllocRingBuffer::new(2)); @@ -1109,9 +1187,9 @@ mod tests { b.push(1); b.push(2); - assert_eq!(b.get(-1), Some(&2)); - assert_eq!(b.get(-2), Some(&1)); - assert_eq!(b.get(-3), Some(&0)) + assert_eq!(b.get_signed(-1), Some(&2)); + assert_eq!(b.get_signed(-2), Some(&1)); + assert_eq!(b.get_signed(-3), Some(&0)) } #[test] @@ -1135,8 +1213,8 @@ mod tests { rb.push(1); rb.push(2); - assert_eq!(rb.get(-1), Some(&2)); - assert_eq!(rb.get(-2), Some(&1)); + assert_eq!(rb.get_signed(-1), Some(&2)); + assert_eq!(rb.get_signed(-2), Some(&1)); } } diff --git a/src/ringbuffer_trait.rs b/src/ringbuffer_trait.rs index 0c60f1c..ae92f09 100644 --- a/src/ringbuffer_trait.rs +++ b/src/ringbuffer_trait.rs @@ -19,7 +19,7 @@ use alloc::vec::Vec; /// implementation, since these safety guarantees are necessary for /// [`iter_mut`](RingBuffer::iter_mut) to work pub unsafe trait RingBuffer: - Sized + IntoIterator + Extend + Index + IndexMut + Sized + IntoIterator + Extend + Index + IndexMut { /// Returns the length of the internal buffer. /// This length grows up to the capacity and then stops growing. @@ -55,6 +55,12 @@ pub unsafe trait RingBuffer: unsafe { Self::ptr_capacity(self) } } + /// Returns the number of elements allocated for this ringbuffer (can be larger than capacity). + fn buffer_size(&self) -> usize { + // Safety: self is a RingBuffer + unsafe { Self::ptr_buffer_size(self) } + } + /// Raw pointer version of capacity. /// /// # Safety @@ -62,6 +68,13 @@ pub unsafe trait RingBuffer: #[doc(hidden)] unsafe fn ptr_capacity(rb: *const Self) -> usize; + /// Raw pointer version of `buffer_size`. + /// + /// # Safety + /// ONLY SAFE WHEN self is a *mut to to an implementor of `RingBuffer` + #[doc(hidden)] + unsafe fn ptr_buffer_size(rb: *const Self) -> usize; + /// Pushes a value onto the buffer. Cycles around if capacity is reached. fn push(&mut self, value: T); @@ -130,12 +143,22 @@ pub unsafe trait RingBuffer: /// Gets a value relative to the current index. 0 is the next index to be written to with push. /// -1 and down are the last elements pushed and 0 and up are the items that were pushed the longest ago. - fn get(&self, index: isize) -> Option<&T>; + fn get_signed(&self, index: isize) -> Option<&T>; + + /// Gets a value relative to the current index. 0 is the next index to be written to with push. + fn get(&self, index: usize) -> Option<&T>; /// Gets a value relative to the current index mutably. 0 is the next index to be written to with push. /// -1 and down are the last elements pushed and 0 and up are the items that were pushed the longest ago. #[inline] - fn get_mut(&mut self, index: isize) -> Option<&mut T> { + fn get_mut_signed(&mut self, index: isize) -> Option<&mut T> { + // Safety: self is a RingBuffer + unsafe { Self::ptr_get_mut_signed(self, index).map(|i| &mut *i) } + } + + /// Gets a value relative to the current index mutably. 0 is the next index to be written to with push. + #[inline] + fn get_mut(&mut self, index: usize) -> Option<&mut T> { // Safety: self is a RingBuffer unsafe { Self::ptr_get_mut(self, index).map(|i| &mut *i) } } @@ -145,7 +168,14 @@ pub unsafe trait RingBuffer: /// # 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>; + unsafe fn ptr_get_mut(rb: *mut Self, index: usize) -> Option<*mut T>; + + /// 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_signed(rb: *mut Self, index: isize) -> Option<*mut T>; /// Returns the value at the current index. /// This is the value that will be overwritten by the next push and also the value pushed @@ -176,14 +206,14 @@ pub unsafe trait RingBuffer: /// This is the item that was pushed most recently. #[inline] fn back(&self) -> Option<&T> { - self.get(-1) + self.get_signed(-1) } /// Returns a mutable reference to the value at the back of the queue. /// This is the item that was pushed most recently. #[inline] fn back_mut(&mut self) -> Option<&mut T> { - self.get_mut(-1) + self.get_mut_signed(-1) } /// Creates a mutable iterator over the buffer starting from the item pushed the longest ago, @@ -251,7 +281,7 @@ mod iter { #[inline] fn next(&mut self) -> Option { if self.index < self.len { - let res = self.obj.get(self.index as isize); + let res = self.obj.get(self.index); self.index += 1; res } else { @@ -272,7 +302,7 @@ mod iter { #[inline] fn next_back(&mut self) -> Option { if self.len > 0 && self.index < self.len { - let res = self.obj.get((self.len - 1) as isize); + let res = self.obj.get(self.len - 1); self.len -= 1; res } else { @@ -315,7 +345,7 @@ mod iter { fn next_back(&mut self) -> Option { if self.len > 0 && self.index < self.len { self.len -= 1; - let res = unsafe { RB::ptr_get_mut(self.obj.as_ptr(), self.len as isize) }; + let res = unsafe { RB::ptr_get_mut(self.obj.as_ptr(), self.len) }; res.map(|i| unsafe { &mut *i }) } else { None @@ -328,7 +358,7 @@ mod iter { fn next(&mut self) -> Option { if self.index < self.len { - let res = unsafe { RB::ptr_get_mut(self.obj.as_ptr(), self.index as isize) }; + let res = unsafe { RB::ptr_get_mut(self.obj.as_ptr(), self.index) }; self.index += 1; // Safety: ptr_get_mut always returns a valid pointer res.map(|i| unsafe { &mut *i }) @@ -420,7 +450,7 @@ macro_rules! impl_ringbuffer { macro_rules! impl_ringbuffer_ext { ($get_unchecked: ident, $get_unchecked_mut: ident, $readptr: ident, $writeptr: ident, $mask: expr) => { #[inline] - fn get(&self, index: isize) -> Option<&T> { + fn get_signed(&self, index: isize) -> Option<&T> { use core::ops::Not; self.is_empty().not().then(move || { let index_from_readptr = if index >= 0 { @@ -435,16 +465,27 @@ macro_rules! impl_ringbuffer_ext { unsafe { // SAFETY: index has been modulo-ed to be within range // to be within bounds - $get_unchecked( - self, - $crate::mask(self.capacity(), normalized_index as usize), - ) + $get_unchecked(self, $mask(self.buffer_size(), normalized_index as usize)) + } + }) + } + + #[inline] + fn get(&self, index: usize) -> Option<&T> { + use core::ops::Not; + self.is_empty().not().then(move || { + let normalized_index = self.$readptr + index.rem_euclid(self.len()); + unsafe { + // SAFETY: index has been modulo-ed to be within range + // to be within bounds + $get_unchecked(self, $mask(self.buffer_size(), normalized_index)) } }) } #[inline] - unsafe fn ptr_get_mut(rb: *mut Self, index: isize) -> Option<*mut T> { + #[doc(hidden)] + unsafe fn ptr_get_mut_signed(rb: *mut Self, index: isize) -> Option<*mut T> { (Self::ptr_len(rb) != 0).then(move || { let index_from_readptr = if index >= 0 { index @@ -460,12 +501,26 @@ macro_rules! impl_ringbuffer_ext { // to be within bounds $get_unchecked_mut( rb, - $crate::mask(Self::ptr_capacity(rb), normalized_index as usize), + $mask(Self::ptr_buffer_size(rb), normalized_index as usize), ) } }) } + #[inline] + #[doc(hidden)] + unsafe fn ptr_get_mut(rb: *mut Self, index: usize) -> Option<*mut T> { + (Self::ptr_len(rb) != 0).then(move || { + let normalized_index = (*rb).$readptr + index.rem_euclid(Self::ptr_len(rb)); + + unsafe { + // SAFETY: index has been modulo-ed to be within range + // to be within bounds + $get_unchecked_mut(rb, $mask(Self::ptr_buffer_size(rb), normalized_index)) + } + }) + } + #[inline] fn clear(&mut self) { for i in self.drain() { diff --git a/src/with_alloc/alloc_ringbuffer.rs b/src/with_alloc/alloc_ringbuffer.rs index 71042a0..730b67d 100644 --- a/src/with_alloc/alloc_ringbuffer.rs +++ b/src/with_alloc/alloc_ringbuffer.rs @@ -7,7 +7,7 @@ use crate::ringbuffer_trait::{ extern crate alloc; // We need boxes, so depend on alloc -use crate::{mask, GrowableAllocRingBuffer}; +use crate::{mask_and, GrowableAllocRingBuffer}; use core::ptr; /// The `AllocRingBuffer` is a `RingBuffer` which is based on a Vec. This means it allocates at runtime @@ -24,7 +24,7 @@ use core::ptr; /// buffer.push(5); /// /// // The last item we pushed is 5 -/// assert_eq!(buffer.get(-1), Some(&5)); +/// assert_eq!(buffer.back(), Some(&5)); /// /// // Second entry is now 42. /// buffer.push(42); @@ -221,13 +221,19 @@ unsafe impl RingBuffer for AllocRingBuffer { (*rb).capacity } + #[inline] + unsafe fn ptr_buffer_size(rb: *const Self) -> usize { + (*rb).size + } + impl_ringbuffer!(readptr, writeptr); #[inline] fn push(&mut self, value: T) { if self.is_full() { + // mask with and is allowed here because size is always a power of two let previous_value = - unsafe { ptr::read(get_unchecked_mut(self, mask(self.size, self.readptr))) }; + unsafe { ptr::read(get_unchecked_mut(self, mask_and(self.size, self.readptr))) }; // make sure we drop whatever is being overwritten // SAFETY: the buffer is full, so this must be initialized @@ -240,7 +246,8 @@ unsafe impl RingBuffer for AllocRingBuffer { self.readptr += 1; } - let index = mask(self.size, self.writeptr); + // mask with and is allowed here because size is always a power of two + let index = mask_and(self.size, self.writeptr); unsafe { ptr::write(get_unchecked_mut(self, index), value); @@ -253,7 +260,8 @@ unsafe impl RingBuffer for AllocRingBuffer { if self.is_empty() { None } else { - let index = mask(self.size, self.readptr); + // mask with and is allowed here because size is always a power of two + let index = mask_and(self.size, self.readptr); let res = unsafe { get_unchecked_mut(self, index) }; self.readptr += 1; @@ -264,7 +272,13 @@ unsafe impl RingBuffer for AllocRingBuffer { } } - impl_ringbuffer_ext!(get_unchecked, get_unchecked_mut, readptr, writeptr, mask); + impl_ringbuffer_ext!( + get_unchecked, + get_unchecked_mut, + readptr, + writeptr, + mask_and + ); #[inline] fn fill_with T>(&mut self, mut f: F) { @@ -340,16 +354,16 @@ unsafe fn get_unchecked_mut(rb: *mut AllocRingBuffer, index: usize) -> *mu p.cast() } -impl Index for AllocRingBuffer { +impl Index for AllocRingBuffer { type Output = T; - fn index(&self, index: isize) -> &Self::Output { + fn index(&self, index: usize) -> &Self::Output { self.get(index).expect("index out of bounds") } } -impl IndexMut for AllocRingBuffer { - fn index_mut(&mut self, index: isize) -> &mut Self::Output { +impl IndexMut for AllocRingBuffer { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { self.get_mut(index).expect("index out of bounds") } } @@ -414,7 +428,7 @@ mod tests { let expected = [0, 0, 1, 2]; for i in 0..4 { - let actual = buf[i as isize]; + let actual = buf[i]; let expected = expected[i]; assert_eq!(actual, expected); } @@ -431,7 +445,7 @@ mod tests { let expected = [2, 3, 4, 5, 6, 7, 8, 9]; for i in 0..8 { - let actual = buf[i as isize]; + let actual = buf[i]; let expected = expected[i]; assert_eq!(actual, expected); } diff --git a/src/with_alloc/vecdeque.rs b/src/with_alloc/vecdeque.rs index 8dbd1f1..23adeb1 100644 --- a/src/with_alloc/vecdeque.rs +++ b/src/with_alloc/vecdeque.rs @@ -173,9 +173,14 @@ unsafe impl RingBuffer for GrowableAllocRingBuffer { (*rb).0.len() } + #[inline] unsafe fn ptr_capacity(rb: *const Self) -> usize { (*rb).0.capacity() } + #[inline] + unsafe fn ptr_buffer_size(rb: *const Self) -> usize { + (*rb).0.capacity() + } fn dequeue(&mut self) -> Option { self.pop_front() @@ -199,7 +204,15 @@ unsafe impl RingBuffer for GrowableAllocRingBuffer { self.0.clear(); } - fn get(&self, index: isize) -> Option<&T> { + fn get(&self, index: usize) -> Option<&T> { + if self.is_empty() { + None + } else { + self.0.get(crate::mask_modulo(self.0.len(), index)) + } + } + + fn get_signed(&self, index: isize) -> Option<&T> { if self.is_empty() { None } else if index >= 0 { @@ -213,7 +226,7 @@ unsafe impl RingBuffer for GrowableAllocRingBuffer { } } - unsafe fn ptr_get_mut(rb: *mut Self, index: isize) -> Option<*mut T> { + unsafe fn ptr_get_mut_signed(rb: *mut Self, index: isize) -> Option<*mut T> { #[allow(trivial_casts)] if RingBuffer::ptr_len(rb) == 0 { None @@ -230,6 +243,16 @@ unsafe impl RingBuffer for GrowableAllocRingBuffer { } .map(|i| i as *mut T) } + + unsafe fn ptr_get_mut(rb: *mut Self, index: usize) -> Option<*mut T> { + #[allow(trivial_casts)] + if RingBuffer::ptr_len(rb) == 0 { + None + } else { + (*rb).0.get_mut(index) + } + .map(|i| i as *mut T) + } } impl Extend for GrowableAllocRingBuffer { @@ -238,16 +261,16 @@ impl Extend for GrowableAllocRingBuffer { } } -impl Index for GrowableAllocRingBuffer { +impl Index for GrowableAllocRingBuffer { type Output = T; - fn index(&self, index: isize) -> &Self::Output { + fn index(&self, index: usize) -> &Self::Output { self.get(index).expect("index out of bounds") } } -impl IndexMut for GrowableAllocRingBuffer { - fn index_mut(&mut self, index: isize) -> &mut Self::Output { +impl IndexMut for GrowableAllocRingBuffer { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { self.get_mut(index).expect("index out of bounds") } } diff --git a/src/with_const_generics.rs b/src/with_const_generics.rs index e7eabd9..e4b6570 100644 --- a/src/with_const_generics.rs +++ b/src/with_const_generics.rs @@ -21,7 +21,7 @@ use core::ops::{Index, IndexMut}; /// buffer.push(5); /// /// // The last item we pushed is 5 -/// assert_eq!(buffer.get(-1), Some(&5)); +/// assert_eq!(buffer.back(), Some(&5)); /// /// // Second entry is now 42. /// buffer.push(42); @@ -257,6 +257,11 @@ unsafe impl RingBuffer for ConstGenericRingBuffer usize { + CAP + } + impl_ringbuffer!(readptr, writeptr); #[inline] @@ -333,16 +338,16 @@ impl FromIterator for ConstGenericRingBuffer } } -impl Index for ConstGenericRingBuffer { +impl Index for ConstGenericRingBuffer { type Output = T; - fn index(&self, index: isize) -> &Self::Output { + fn index(&self, index: usize) -> &Self::Output { self.get(index).expect("index out of bounds") } } -impl IndexMut for ConstGenericRingBuffer { - fn index_mut(&mut self, index: isize) -> &mut Self::Output { +impl IndexMut for ConstGenericRingBuffer { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { self.get_mut(index).expect("index out of bounds") } } @@ -390,7 +395,7 @@ mod tests { let expected = [0, 0, 1, 2]; for i in 0..4 { - let actual = buf[i as isize]; + let actual = buf[i]; let expected = expected[i]; assert_eq!(actual, expected); } @@ -407,9 +412,85 @@ mod tests { let expected = [2, 3, 4, 5, 6, 7, 8, 9]; for i in 0..8 { - let actual = buf[i as isize]; + let actual = buf[i]; let expected = expected[i]; assert_eq!(actual, expected); } } + + #[cfg(test)] + mod tests { + use crate::{AllocRingBuffer, ConstGenericRingBuffer, GrowableAllocRingBuffer, RingBuffer}; + use alloc::collections::{LinkedList, VecDeque}; + use alloc::string::ToString; + use alloc::vec; + + #[test] + fn from() { + assert_eq!( + ConstGenericRingBuffer::::from([1, 2, 3]).to_vec(), + vec![1, 2, 3] + ); + + let v: &[i32; 3] = &[1, 2, 3]; + assert_eq!( + ConstGenericRingBuffer::::from(v).to_vec(), + vec![1, 2, 3] + ); + + let v: &[i32] = &[1, 2, 3]; + assert_eq!( + ConstGenericRingBuffer::::from(v).to_vec(), + vec![1, 2, 3] + ); + + let v: &mut [i32; 3] = &mut [1, 2, 3]; + assert_eq!( + ConstGenericRingBuffer::::from(v).to_vec(), + vec![1, 2, 3] + ); + + let v: &mut [i32] = &mut [1, 2, 3]; + assert_eq!( + ConstGenericRingBuffer::::from(v).to_vec(), + vec![1, 2, 3] + ); + + assert_eq!( + ConstGenericRingBuffer::::from(vec![1, 2, 3]).to_vec(), + vec![1, 2, 3] + ); + assert_eq!( + ConstGenericRingBuffer::::from( + vec![1, 2, 3].into_iter().collect::>() + ) + .to_vec(), + vec![1, 2, 3] + ); + assert_eq!( + ConstGenericRingBuffer::::from( + vec![1, 2, 3].into_iter().collect::>() + ) + .to_vec(), + vec![1, 2, 3] + ); + assert_eq!( + ConstGenericRingBuffer::<_, 3>::from("abc".to_string()).to_vec(), + vec!['a', 'b', 'c'] + ); + assert_eq!( + ConstGenericRingBuffer::<_, 3>::from("abc").to_vec(), + vec!['a', 'b', 'c'] + ); + assert_eq!( + ConstGenericRingBuffer::<_, 3>::from(GrowableAllocRingBuffer::from(vec![1, 2, 3])) + .to_vec(), + vec![1, 2, 3] + ); + assert_eq!( + ConstGenericRingBuffer::<_, 3>::from(AllocRingBuffer::from(vec![1, 2, 3])).to_vec(), + vec![1, 2, 3] + ); + } + } } diff --git a/tests/compile-fail/test_const_generic_array_zero_length.rs b/tests/compile-fail/test_const_generic_array_zero_length.rs deleted file mode 100644 index 3b69f1a..0000000 --- a/tests/compile-fail/test_const_generic_array_zero_length.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern crate ringbuffer; - -use ringbuffer::ConstGenericRingBuffer; - -fn main() { - let _ = ConstGenericRingBuffer::::new(); - //~^ note: the above error was encountered while instantiating `fn ringbuffer::ConstGenericRingBuffer::::new::<0>` - // ringbuffer can't be zero length -} diff --git a/tests/compile-fail/test_const_generic_array_zero_length_new.rs b/tests/compile-fail/test_const_generic_array_zero_length_new.rs deleted file mode 100644 index b080de1..0000000 --- a/tests/compile-fail/test_const_generic_array_zero_length_new.rs +++ /dev/null @@ -1,10 +0,0 @@ -extern crate ringbuffer; - -use ringbuffer::{ConstGenericRingBuffer, RingBuffer}; - -fn main() { - let mut buf = ConstGenericRingBuffer::new::<0>(); - //~^ note: the above error was encountered while instantiating `fn ringbuffer::ConstGenericRingBuffer::::new::<0>` - // ringbuffer can't be zero length - buf.push(5); -} diff --git a/tests/compiletests.rs b/tests/compiletests.rs deleted file mode 100644 index f48163e..0000000 --- a/tests/compiletests.rs +++ /dev/null @@ -1,23 +0,0 @@ -extern crate compiletest_rs as compiletest; - -use std::path::PathBuf; - -#[cfg(test)] -mod conversions; - -fn run_mode(mode: &'static str) { - let mut config = compiletest::Config::default(); - - config.mode = mode.parse().expect("Invalid mode"); - config.src_base = PathBuf::from(format!("tests/{}", mode)); - config.link_deps(); // Populate config.target_rustcflags with dependencies on the path - config.clean_rmeta(); // If your tests import the parent crate, this helps with E0464 - - compiletest::run_tests(&config); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn compile_test() { - run_mode("compile-fail"); -} diff --git a/tests/conversions.rs b/tests/conversions.rs deleted file mode 100644 index e3c13a2..0000000 --- a/tests/conversions.rs +++ /dev/null @@ -1,135 +0,0 @@ -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 std::vec; - -macro_rules! convert_test { - ($name: ident: $from: expr => $to: ty) => { - #[test] - fn $name() { - let a = $from; - - let mut b: $to = a.into(); - assert_eq!(b.to_vec(), vec!['1', '2']); - b.push('3'); - assert_eq!(b, b); - } - }; -} - -macro_rules! convert_tests { - ( - [$($name: ident: $from: expr),* $(,)?] - => $to: ty - ) => { - $( - convert_test!($name: $from => $to); - )* - }; -} - -convert_tests!( - [ - alloc_from_vec: vec!['1', '2'], - alloc_from_ll: {let mut l = LinkedList::new(); l.push_back('1'); l.push_back('2'); l}, - alloc_from_vd: {let mut l = VecDeque::new(); l.push_back('1'); l.push_back('2'); l}, - alloc_from_str: "12".to_string(), - alloc_from_str_slice: "12", - alloc_from_slice: {let a: &[char] = &['1', '2']; a}, - alloc_from_const_slice: {let a: &[char; 2] = &['1', '2']; a}, - alloc_from_arr: {let a: [char; 2] = ['1', '2']; a}, - - alloc_from_cgrb: {let a = ConstGenericRingBuffer::from(['1', '2']); a}, - alloc_from_garb: {let a = GrowableAllocRingBuffer::from(['1', '2']); a}, - ] => AllocRingBuffer::<_> -); - -convert_tests!( - [ - growable_alloc_from_vec: vec!['1', '2'], - growable_alloc_from_ll: {let mut l = LinkedList::new(); l.push_back('1'); l.push_back('2'); l}, - growable_alloc_from_vd: {let mut l = VecDeque::new(); l.push_back('1'); l.push_back('2'); l}, - growable_alloc_from_str: "12".to_string(), - growable_alloc_from_str_slice: "12", - growable_alloc_from_slice: {let a: &[char] = &['1', '2']; a}, - growable_alloc_from_const_slice: {let a: &[char; 2] = &['1', '2']; a}, - growable_alloc_from_arr: {let a: [char; 2] = ['1', '2']; a}, - - growable_alloc_from_cgrb: {let a = ConstGenericRingBuffer::from(['1', '2']); a}, - growable_alloc_from_arb: {let a = AllocRingBuffer::from(['1', '2']); a}, - ] => GrowableAllocRingBuffer::<_> -); - -convert_tests!( - [ - const_from_vec: vec!['1', '2'], - const_from_ll: {let mut l = LinkedList::new(); l.push_back('1'); l.push_back('2'); l}, - const_from_vd: {let mut l = VecDeque::new(); l.push_back('1'); l.push_back('2'); l}, - const_from_str: "12".to_string(), - const_from_str_slice: "12", - const_from_slice: {let a: &[char] = &['1', '2']; a}, - const_from_const_slice: {let a: &[char; 2] = &['1', '2']; a}, - const_from_arr: {let a: [char; 2] = ['1', '2']; a}, - - const_from_garb: {let a = GrowableAllocRingBuffer::from(['1', '2']); a}, - const_from_arb: {let a = AllocRingBuffer::from(['1', '2']); a}, - ] => ConstGenericRingBuffer::<_, 2> -); - -#[test] -fn test_extra_conversions_growable() { - let a: &mut [i32; 2] = &mut [1, 2]; - let a = GrowableAllocRingBuffer::from(a); - assert_eq!(a.to_vec(), vec![1, 2]); - - let a: &mut [i32] = &mut [1, 2]; - let a = GrowableAllocRingBuffer::from(a); - assert_eq!(a.to_vec(), vec![1, 2]); - - let mut b = VecDeque::::new(); - b.push_back(1); - b.push_back(2); - assert_eq!(a.deref(), &b); - assert_eq!(a.as_ref(), &b); -} - -#[test] -fn test_extra_conversions_alloc() { - let a: &mut [i32; 2] = &mut [1, 2]; - let a = AllocRingBuffer::from(a); - assert_eq!(a.to_vec(), vec![1, 2]); - - let a: &mut [i32] = &mut [1, 2]; - let a = AllocRingBuffer::from(a); - assert_eq!(a.to_vec(), vec![1, 2]); -} - -#[test] -fn test_extra_conversions_const() { - let a: &mut [i32; 2] = &mut [1, 2]; - let a = ConstGenericRingBuffer::<_, 2>::from(a); - assert_eq!(a.to_vec(), vec![1, 2]); - - let a: &mut [i32] = &mut [1, 2]; - let a = ConstGenericRingBuffer::<_, 2>::from(a); - assert_eq!(a.to_vec(), vec![1, 2]); -} - -#[test] -fn test_const_generic_new_parameter() { - // Can we specify size only on the method? - let mut a = ConstGenericRingBuffer::new::<2>(); - a.push(5); - - // Can we specify size in both positions? - let mut a = ConstGenericRingBuffer::::new::<50>(); - a.push(5); - - // Can we specify size only on the struct? - let mut a = ConstGenericRingBuffer::::new(); - a.push(5); -}