diff --git a/CHANGELOG.md b/CHANGELOG.md index 63644e83bea9b5fee8572bdd27dbbbf734065bfa..90c05302f39ef98388d8ac5f7a2461446c45dacc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,27 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.2.0] - 2017-11-22 + +### Added + +- A single producer single consumer mode to `RingBuffer`. + +- A `truncate` method to `Vec`. + +### Changed + +- [breaking-change] Both `Vec::new` and `RingBuffer::new` no longer require an initial value. The + signature of `new` is now `const fn() -> Self`. + +- [breaking-change] The error type of all operations that may fail has changed from `()` to + `BufferFullError`. + +- Both `RingBuffer` and `Vec` now support arrays of *any* size for their backup storage. + ## [v0.1.0] - 2017-04-27 - Initial release -[Unreleased]: https://github.com/japaric/heapless/compare/v0.1.0...HEAD +[Unreleased]: https://github.com/japaric/heapless/compare/v0.2.0...HEAD +[v0.2.0]: https://github.com/japaric/heapless/compare/v0.1.0...v0.2.0 diff --git a/src/ring_buffer/mod.rs b/src/ring_buffer/mod.rs index 0ae68a7c909c67b0f5f044e8336d7a1da33196f9..faa5f0bbff6081c9d8434b054b347b28ebe6da2c 100644 --- a/src/ring_buffer/mod.rs +++ b/src/ring_buffer/mod.rs @@ -6,9 +6,8 @@ use core::{intrinsics, ptr}; use untagged_option::UntaggedOption; -use BufferFullError; - pub use self::spsc::{Consumer, Producer}; +use BufferFullError; mod spsc; diff --git a/src/ring_buffer/spsc.rs b/src/ring_buffer/spsc.rs index 4260baec7b143a32f3a0f13c37c88f9cd1ac02fd..955d7744fdd6e32e8db302b570ae26581794e1c7 100644 --- a/src/ring_buffer/spsc.rs +++ b/src/ring_buffer/spsc.rs @@ -1,5 +1,5 @@ -use core::ptr::{self, Shared}; use core::marker::{PhantomData, Unsize}; +use core::ptr::{self, Shared}; use BufferFullError; use ring_buffer::RingBuffer; @@ -89,6 +89,10 @@ where let buffer: &mut [T] = unsafe { rb.buffer.as_mut() }; let tail = rb.tail.load_relaxed(); + // NOTE we could replace this `load_acquire` with a `load_relaxed` and this method would be + // sound on most architectures but that change would result in UB according to the C++ + // memory model, which is what Rust currently uses, so we err on the side of caution and + // stick to `load_acquire`. Check issue google#sanitizers#882 for more details. let head = rb.head.load_acquire(); let next_tail = (tail + 1) % n; if next_tail != head { diff --git a/src/vec.rs b/src/vec.rs index 9140cde1d14caa18682e83de5a84e5a94d468465..e1b91ecb47b67618aff18a1c740ae961bd673dc3 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -37,6 +37,11 @@ where buffer.len() } + /// Clears the vector, removing all values. + pub fn clear(&mut self) { + self.truncate(0); + } + /// Removes the last element from a vector and return it, or `None` if it's empty pub fn pop(&mut self) -> Option<T> { let buffer: &[T] = unsafe { self.buffer.as_ref() }; @@ -67,6 +72,20 @@ where Err(BufferFullError) } } + + /// Shortens the vector, keeping the first `len` elements and dropping the rest. + pub fn truncate(&mut self, len: usize) { + unsafe { + // drop any extra elements + while len < self.len { + // decrement len before the drop_in_place(), so a panic on Drop + // doesn't re-drop the just-failed value. + self.len -= 1; + let len = self.len; + ptr::drop_in_place(self.get_unchecked_mut(len)); + } + } + } } impl<T, A> Drop for Vec<T, A>