diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0bea10baa6..26692f7c2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `VecView`, the `!Sized` version of `Vec`.
- Added pool implementations for 64-bit architectures.
- Added `IntoIterator` implementation for `LinearMap`
+- Added `spsc::QueueView`, the `!Sized` version of `spsc::Queue`.
### Changed
diff --git a/src/spsc.rs b/src/spsc.rs
index 1b7ab0354b..9da343a77b 100644
--- a/src/spsc.rs
+++ b/src/spsc.rs
@@ -97,7 +97,7 @@
//! - The numbers reported correspond to the successful path (i.e. `Some` is returned by `dequeue`
//! and `Ok` is returned by `enqueue`).
-use core::{cell::UnsafeCell, fmt, hash, mem::MaybeUninit, ptr};
+use core::{cell::UnsafeCell, fmt, hash, marker::PhantomData, mem::MaybeUninit, ptr};
#[cfg(not(feature = "portable-atomic"))]
use core::sync::atomic;
@@ -106,26 +106,106 @@ use portable_atomic as atomic;
use atomic::{AtomicUsize, Ordering};
+mod private {
+ use super::*;
+
+ ///
This is private API and should not be used
+ pub struct QueueInner {
+ // this is from where we dequeue items
+ pub(crate) head: AtomicUsize,
+
+ // this is where we enqueue new items
+ pub(crate) tail: AtomicUsize,
+
+ pub(crate) buffer: B,
+ }
+
+ pub trait QueueBuffer {
+ type T;
+ fn as_view(this: &QueueInner) -> &QueueView;
+ fn as_mut_view(this: &mut QueueInner) -> &mut QueueView;
+ }
+}
+
+// Workaround https://github.com/rust-lang/rust/issues/119015. This is required so that the methods on `Queue` and `QueueView` are properly documented.
+// cfg(doc) prevents `QueueInner` being part of the public API.
+// doc(hidden) prevents the `pub use vec::VecInner` from being visible in the documentation.
+#[cfg(doc)]
+#[doc(hidden)]
+pub use private::QueueInner as _;
+
/// A statically allocated single producer single consumer queue with a capacity of `N - 1` elements
///
/// *IMPORTANT*: To get better performance use a value for `N` that is a power of 2 (e.g. `16`, `32`,
/// etc.).
-pub struct Queue {
- // this is from where we dequeue items
- pub(crate) head: AtomicUsize,
+pub type Queue = private::QueueInner<[UnsafeCell>; N]>;
+
+/// A statically allocated single producer single consumer queue with dynamic capacity
+pub type QueueView = private::QueueInner<[UnsafeCell>]>;
+
+impl private::QueueBuffer for [UnsafeCell>; N] {
+ type T = T;
+
+ fn as_view(this: &private::QueueInner) -> &QueueView {
+ this
+ }
+ fn as_mut_view(this: &mut private::QueueInner) -> &mut QueueView {
+ this
+ }
+}
- // this is where we enqueue new items
- pub(crate) tail: AtomicUsize,
+impl private::QueueBuffer for [UnsafeCell>] {
+ type T = T;
- pub(crate) buffer: [UnsafeCell>; N],
+ fn as_view(this: &private::QueueInner) -> &QueueView {
+ this
+ }
+ fn as_mut_view(this: &mut private::QueueInner) -> &mut QueueView {
+ this
+ }
}
impl Queue {
const INIT: UnsafeCell> = UnsafeCell::new(MaybeUninit::uninit());
- #[inline]
- fn increment(val: usize) -> usize {
- (val + 1) % N
+ /// Get a reference to the `Queue`, erasing the `N` const-generic.
+ ///
+ /// ```
+ /// use heapless::spsc::{Queue, QueueView};
+ ///
+ /// let rb: Queue = Queue::new();
+ /// let rb_view: &QueueView = rb.as_view();
+ /// ```
+ /// It is often preferable to do the same through type coerction, since `Queue` implements `Unsize>`:
+ ///
+ /// ```
+ /// use heapless::spsc::{Queue, QueueView};
+ ///
+ /// let rb: Queue = Queue::new();
+ /// let rb_view: &QueueView = &rb;
+ /// ```
+ pub fn as_view(&self) -> &QueueView {
+ self
+ }
+
+ /// Get a mutable reference to the `Queue`, erasing the `N` const-generic.
+ ///
+ /// ```
+ /// use heapless::spsc::{Queue, QueueView};
+ ///
+ /// let mut rb: Queue = Queue::new();
+ /// let rb_view: &mut QueueView = rb.as_mut_view();
+ /// ```
+ /// It is often preferable to do the same through type coerction, since `Queue` implements `Unsize>`:
+ ///
+ /// ```
+ /// use heapless::spsc::{Queue, QueueView};
+ ///
+ /// let mut rb: Queue = Queue::new();
+ /// let rb_view: &mut QueueView = &mut rb;
+ /// ```
+ pub fn as_mut_view(&mut self) -> &mut QueueView {
+ self
}
/// Creates an empty queue with a fixed capacity of `N - 1`
@@ -146,13 +226,138 @@ impl Queue {
N - 1
}
+ /// Returns the number of elements in the queue
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.as_view().len()
+ }
+
+ /// Returns `true` if the queue is empty
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.as_view().is_empty()
+ }
+
+ /// Returns `true` if the queue is full
+ #[inline]
+ pub fn is_full(&self) -> bool {
+ self.as_view().is_full()
+ }
+
+ /// Iterates from the front of the queue to the back
+ pub fn iter(&self) -> Iter<'_, T, N> {
+ Iter {
+ inner: self.as_view().iter(),
+ phantom: PhantomData,
+ }
+ }
+
+ /// Returns an iterator that allows modifying each value
+ pub fn iter_mut(&mut self) -> IterMut<'_, T, N> {
+ IterMut {
+ inner: self.as_mut_view().iter_mut(),
+ phantom: PhantomData,
+ }
+ }
+
+ /// Adds an `item` to the end of the queue
+ ///
+ /// Returns back the `item` if the queue is full
+ #[inline]
+ pub fn enqueue(&mut self, val: T) -> Result<(), T> {
+ self.as_mut_view().enqueue(val)
+ }
+
+ /// Returns the item in the front of the queue, or `None` if the queue is empty
+ #[inline]
+ pub fn dequeue(&mut self) -> Option {
+ self.as_mut_view().dequeue()
+ }
+
+ /// Returns a reference to the item in the front of the queue without dequeuing, or
+ /// `None` if the queue is empty.
+ ///
+ /// # Examples
+ /// ```
+ /// use heapless::spsc::Queue;
+ ///
+ /// let mut queue: Queue = Queue::new();
+ /// let (mut producer, mut consumer) = queue.split();
+ /// assert_eq!(None, consumer.peek());
+ /// producer.enqueue(1);
+ /// assert_eq!(Some(&1), consumer.peek());
+ /// assert_eq!(Some(1), consumer.dequeue());
+ /// assert_eq!(None, consumer.peek());
+ /// ```
+ pub fn peek(&self) -> Option<&T> {
+ self.as_view().peek()
+ }
+
+ /// Adds an `item` to the end of the queue, without checking if it's full
+ ///
+ /// # Safety
+ ///
+ /// If the queue is full this operation will leak a value (T's destructor won't run on
+ /// the value that got overwritten by `item`), *and* will allow the `dequeue` operation
+ /// to create a copy of `item`, which could result in `T`'s destructor running on `item`
+ /// twice.
+ pub unsafe fn enqueue_unchecked(&mut self, val: T) {
+ self.as_mut_view().inner_enqueue_unchecked(val)
+ }
+
+ /// Returns the item in the front of the queue, without checking if there is something in the
+ /// queue
+ ///
+ /// # Safety
+ ///
+ /// If the queue is empty this operation will return uninitialized memory.
+ pub unsafe fn dequeue_unchecked(&mut self) -> T {
+ self.as_mut_view().dequeue_unchecked()
+ }
+
+ /// Splits a queue into producer and consumer endpoints
+ pub fn split(&mut self) -> (Producer<'_, T, N>, Consumer<'_, T, N>) {
+ let (producer, consumer) = self.as_mut_view().split();
+ (
+ Producer {
+ inner: producer,
+ phantom: PhantomData,
+ },
+ Consumer {
+ inner: consumer,
+ phantom: PhantomData,
+ },
+ )
+ }
+}
+
+impl QueueView {
+ #[inline]
+ fn increment(&self, val: usize) -> usize {
+ (val + 1) % self.n()
+ }
+
+ /// Returns the maximum number of elements the queue can hold
+ #[inline]
+ pub const fn capacity(&self) -> usize {
+ self.n() - 1
+ }
+
+ #[inline]
+ const fn n(&self) -> usize {
+ self.buffer.len()
+ }
+
/// Returns the number of elements in the queue
#[inline]
pub fn len(&self) -> usize {
let current_head = self.head.load(Ordering::Relaxed);
let current_tail = self.tail.load(Ordering::Relaxed);
- current_tail.wrapping_sub(current_head).wrapping_add(N) % N
+ current_tail
+ .wrapping_sub(current_head)
+ .wrapping_add(self.n())
+ % self.n()
}
/// Returns `true` if the queue is empty
@@ -164,12 +369,12 @@ impl Queue {
/// Returns `true` if the queue is full
#[inline]
pub fn is_full(&self) -> bool {
- Self::increment(self.tail.load(Ordering::Relaxed)) == self.head.load(Ordering::Relaxed)
+ self.increment(self.tail.load(Ordering::Relaxed)) == self.head.load(Ordering::Relaxed)
}
/// Iterates from the front of the queue to the back
- pub fn iter(&self) -> Iter<'_, T, N> {
- Iter {
+ pub fn iter(&self) -> IterView<'_, T> {
+ IterView {
rb: self,
index: 0,
len: self.len(),
@@ -177,9 +382,9 @@ impl Queue {
}
/// Returns an iterator that allows modifying each value
- pub fn iter_mut(&mut self) -> IterMut<'_, T, N> {
+ pub fn iter_mut(&mut self) -> IterMutView<'_, T> {
let len = self.len();
- IterMut {
+ IterMutView {
rb: self,
index: 0,
len,
@@ -205,10 +410,11 @@ impl Queue {
///
/// # Examples
/// ```
- /// use heapless::spsc::Queue;
+ /// use heapless::spsc::{Queue, QueueView};
///
/// let mut queue: Queue = Queue::new();
- /// let (mut producer, mut consumer) = queue.split();
+ /// let queue_view: &mut QueueView = &mut queue;
+ /// let (mut producer, mut consumer) = queue_view.split();
/// assert_eq!(None, consumer.peek());
/// producer.enqueue(1);
/// assert_eq!(Some(&1), consumer.peek());
@@ -225,11 +431,11 @@ impl Queue {
}
// The memory for enqueueing is "owned" by the tail pointer.
- // NOTE: This internal function uses internal mutability to allow the [`Producer`] to enqueue
+ // NOTE: This internal function uses internal mutability to allow the [`ProducerView`] to enqueue
// items without doing pointer arithmetic and accessing internal fields of this type.
unsafe fn inner_enqueue(&self, val: T) -> Result<(), T> {
let current_tail = self.tail.load(Ordering::Relaxed);
- let next_tail = Self::increment(current_tail);
+ let next_tail = self.increment(current_tail);
if next_tail != self.head.load(Ordering::Acquire) {
(self.buffer.get_unchecked(current_tail).get()).write(MaybeUninit::new(val));
@@ -242,14 +448,14 @@ impl Queue {
}
// The memory for enqueueing is "owned" by the tail pointer.
- // NOTE: This internal function uses internal mutability to allow the [`Producer`] to enqueue
+ // NOTE: This internal function uses internal mutability to allow the [`ProducerView`] to enqueue
// items without doing pointer arithmetic and accessing internal fields of this type.
unsafe fn inner_enqueue_unchecked(&self, val: T) {
let current_tail = self.tail.load(Ordering::Relaxed);
(self.buffer.get_unchecked(current_tail).get()).write(MaybeUninit::new(val));
self.tail
- .store(Self::increment(current_tail), Ordering::Release);
+ .store(self.increment(current_tail), Ordering::Release);
}
/// Adds an `item` to the end of the queue, without checking if it's full
@@ -265,7 +471,7 @@ impl Queue {
}
// The memory for dequeuing is "owned" by the head pointer,.
- // NOTE: This internal function uses internal mutability to allow the [`Consumer`] to dequeue
+ // NOTE: This internal function uses internal mutability to allow the [`ConsumerView`] to dequeue
// items without doing pointer arithmetic and accessing internal fields of this type.
unsafe fn inner_dequeue(&self) -> Option {
let current_head = self.head.load(Ordering::Relaxed);
@@ -276,21 +482,21 @@ impl Queue {
let v = (self.buffer.get_unchecked(current_head).get() as *const T).read();
self.head
- .store(Self::increment(current_head), Ordering::Release);
+ .store(self.increment(current_head), Ordering::Release);
Some(v)
}
}
// The memory for dequeuing is "owned" by the head pointer,.
- // NOTE: This internal function uses internal mutability to allow the [`Consumer`] to dequeue
+ // NOTE: This internal function uses internal mutability to allow the [`ConsumerView`] to dequeue
// items without doing pointer arithmetic and accessing internal fields of this type.
unsafe fn inner_dequeue_unchecked(&self) -> T {
let current_head = self.head.load(Ordering::Relaxed);
let v = (self.buffer.get_unchecked(current_head).get() as *const T).read();
self.head
- .store(Self::increment(current_head), Ordering::Release);
+ .store(self.increment(current_head), Ordering::Release);
v
}
@@ -306,8 +512,8 @@ impl Queue {
}
/// Splits a queue into producer and consumer endpoints
- pub fn split(&mut self) -> (Producer<'_, T, N>, Consumer<'_, T, N>) {
- (Producer { rb: self }, Consumer { rb: self })
+ pub fn split(&mut self) -> (ProducerView<'_, T>, ConsumerView<'_, T>) {
+ (ProducerView { rb: self }, ConsumerView { rb: self })
}
}
@@ -341,20 +547,49 @@ where
T: PartialEq,
{
fn eq(&self, other: &Queue) -> bool {
- self.len() == other.len() && self.iter().zip(other.iter()).all(|(v1, v2)| v1 == v2)
+ self.as_view().eq(other.as_view())
}
}
impl Eq for Queue where T: Eq {}
+impl PartialEq> for QueueView
+where
+ T: PartialEq,
+{
+ fn eq(&self, other: &QueueView) -> bool {
+ self.len() == other.len() && self.iter().zip(other.iter()).all(|(v1, v2)| v1 == v2)
+ }
+}
+
+impl PartialEq> for QueueView
+where
+ T: PartialEq,
+{
+ fn eq(&self, other: &Queue) -> bool {
+ self.eq(other.as_view())
+ }
+}
+
+impl PartialEq> for Queue
+where
+ T: PartialEq,
+{
+ fn eq(&self, other: &QueueView) -> bool {
+ self.as_view().eq(other)
+ }
+}
+
+impl Eq for QueueView where T: Eq {}
+
/// An iterator over the items of a queue
-pub struct Iter<'a, T, const N: usize> {
- rb: &'a Queue,
+pub struct IterView<'a, T> {
+ rb: &'a QueueView,
index: usize,
len: usize,
}
-impl<'a, T, const N: usize> Clone for Iter<'a, T, N> {
+impl<'a, T> Clone for IterView<'a, T> {
fn clone(&self) -> Self {
Self {
rb: self.rb,
@@ -365,20 +600,20 @@ impl<'a, T, const N: usize> Clone for Iter<'a, T, N> {
}
/// A mutable iterator over the items of a queue
-pub struct IterMut<'a, T, const N: usize> {
- rb: &'a mut Queue,
+pub struct IterMutView<'a, T> {
+ rb: &'a mut QueueView,
index: usize,
len: usize,
}
-impl<'a, T, const N: usize> Iterator for Iter<'a, T, N> {
+impl<'a, T> Iterator for IterView<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option {
if self.index < self.len {
let head = self.rb.head.load(Ordering::Relaxed);
- let i = (head + self.index) % N;
+ let i = (head + self.index) % self.rb.n();
self.index += 1;
Some(unsafe { &*(self.rb.buffer.get_unchecked(i).get() as *const T) })
@@ -388,46 +623,46 @@ impl<'a, T, const N: usize> Iterator for Iter<'a, T, N> {
}
}
-impl<'a, T, const N: usize> Iterator for IterMut<'a, T, N> {
- type Item = &'a mut T;
-
- fn next(&mut self) -> Option {
+impl<'a, T> DoubleEndedIterator for IterView<'a, T> {
+ fn next_back(&mut self) -> Option {
if self.index < self.len {
let head = self.rb.head.load(Ordering::Relaxed);
- let i = (head + self.index) % N;
- self.index += 1;
-
- Some(unsafe { &mut *(self.rb.buffer.get_unchecked(i).get() as *mut T) })
+ // self.len > 0, since it's larger than self.index > 0
+ let i = (head + self.len - 1) % self.rb.n();
+ self.len -= 1;
+ Some(unsafe { &*(self.rb.buffer.get_unchecked(i).get() as *const T) })
} else {
None
}
}
}
-impl<'a, T, const N: usize> DoubleEndedIterator for Iter<'a, T, N> {
+impl<'a, T> DoubleEndedIterator for IterMutView<'a, T> {
fn next_back(&mut self) -> Option {
if self.index < self.len {
let head = self.rb.head.load(Ordering::Relaxed);
// self.len > 0, since it's larger than self.index > 0
- let i = (head + self.len - 1) % N;
+ let i = (head + self.len - 1) % self.rb.n();
self.len -= 1;
- Some(unsafe { &*(self.rb.buffer.get_unchecked(i).get() as *const T) })
+ Some(unsafe { &mut *(self.rb.buffer.get_unchecked(i).get() as *mut T) })
} else {
None
}
}
}
-impl<'a, T, const N: usize> DoubleEndedIterator for IterMut<'a, T, N> {
- fn next_back(&mut self) -> Option {
+impl<'a, T> Iterator for IterMutView<'a, T> {
+ type Item = &'a mut T;
+
+ fn next(&mut self) -> Option {
if self.index < self.len {
let head = self.rb.head.load(Ordering::Relaxed);
- // self.len > 0, since it's larger than self.index > 0
- let i = (head + self.len - 1) % N;
- self.len -= 1;
+ let i = (head + self.index) % self.rb.n();
+ self.index += 1;
+
Some(unsafe { &mut *(self.rb.buffer.get_unchecked(i).get() as *mut T) })
} else {
None
@@ -435,9 +670,61 @@ impl<'a, T, const N: usize> DoubleEndedIterator for IterMut<'a, T, N> {
}
}
-impl Drop for Queue {
+/// A mutable iterator over the items of a queue
+pub struct Iter<'a, T, const N: usize> {
+ inner: IterView<'a, T>,
+ /// PhantomData to keep the `N` const generic and avoid a breaking change
+ phantom: PhantomData<[T; N]>,
+}
+
+impl<'a, T, const N: usize> Clone for Iter<'a, T, N> {
+ fn clone(&self) -> Self {
+ Self {
+ inner: self.inner.clone(),
+ phantom: PhantomData,
+ }
+ }
+}
+
+/// A mutable iterator over the items of a queue
+pub struct IterMut<'a, T, const N: usize> {
+ inner: IterMutView<'a, T>,
+ /// PhantomData to keep the `N` const generic and avoid a breaking change
+ phantom: PhantomData<[T; N]>,
+}
+
+impl<'a, T, const N: usize> Iterator for Iter<'a, T, N> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option {
+ self.inner.next()
+ }
+}
+
+impl<'a, T, const N: usize> Iterator for IterMut<'a, T, N> {
+ type Item = &'a mut T;
+
+ fn next(&mut self) -> Option {
+ self.inner.next()
+ }
+}
+
+impl<'a, T, const N: usize> DoubleEndedIterator for Iter<'a, T, N> {
+ fn next_back(&mut self) -> Option {
+ self.inner.next_back()
+ }
+}
+
+impl<'a, T, const N: usize> DoubleEndedIterator for IterMut<'a, T, N> {
+ fn next_back(&mut self) -> Option {
+ self.inner.next_back()
+ }
+}
+
+impl Drop for private::QueueInner {
fn drop(&mut self) {
- for item in self {
+ let this = private::QueueBuffer::as_mut_view(self);
+ for item in this {
unsafe {
ptr::drop_in_place(item);
}
@@ -446,6 +733,15 @@ impl Drop for Queue {
}
impl fmt::Debug for Queue
+where
+ T: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.as_view().fmt(f)
+ }
+}
+
+impl fmt::Debug for QueueView
where
T: fmt::Debug,
{
@@ -455,6 +751,15 @@ where
}
impl hash::Hash for Queue
+where
+ T: hash::Hash,
+{
+ fn hash(&self, state: &mut H) {
+ self.as_view().hash(state)
+ }
+}
+
+impl hash::Hash for QueueView
where
T: hash::Hash,
{
@@ -466,6 +771,24 @@ where
}
}
+impl<'a, T> IntoIterator for &'a QueueView {
+ type Item = &'a T;
+ type IntoIter = IterView<'a, T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a, T> IntoIterator for &'a mut QueueView {
+ type Item = &'a mut T;
+ type IntoIter = IterMutView<'a, T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
impl<'a, T, const N: usize> IntoIterator for &'a Queue {
type Item = &'a T;
type IntoIter = Iter<'a, T, N>;
@@ -487,20 +810,164 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut Queue {
/// A queue "consumer"; it can dequeue items from the queue
/// NOTE the consumer semantically owns the `head` pointer of the queue
pub struct Consumer<'a, T, const N: usize> {
- rb: &'a Queue,
+ phantom: PhantomData<[T; N]>,
+ inner: ConsumerView<'a, T>,
}
-unsafe impl<'a, T, const N: usize> Send for Consumer<'a, T, N> where T: Send {}
-
/// A queue "producer"; it can enqueue items into the queue
/// NOTE the producer semantically owns the `tail` pointer of the queue
pub struct Producer<'a, T, const N: usize> {
- rb: &'a Queue,
+ phantom: PhantomData<[T; N]>,
+ inner: ProducerView<'a, T>,
}
unsafe impl<'a, T, const N: usize> Send for Producer<'a, T, N> where T: Send {}
impl<'a, T, const N: usize> Consumer<'a, T, N> {
+ /// Returns the item in the front of the queue, or `None` if the queue is empty
+ #[inline]
+ pub fn dequeue(&mut self) -> Option {
+ self.inner.dequeue()
+ }
+
+ /// Returns the item in the front of the queue, without checking if there are elements in the
+ /// queue
+ ///
+ /// # Safety
+ ///
+ /// See [`Queue::dequeue_unchecked`]
+ #[inline]
+ pub unsafe fn dequeue_unchecked(&mut self) -> T {
+ self.inner.dequeue_unchecked()
+ }
+
+ /// Returns if there are any items to dequeue. When this returns `true`, at least the
+ /// first subsequent dequeue will succeed
+ #[inline]
+ pub fn ready(&self) -> bool {
+ self.inner.ready()
+ }
+
+ /// Returns the number of elements in the queue
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ /// Returns true if the queue is empty
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use heapless::spsc::Queue;
+ ///
+ /// let mut queue: Queue = Queue::new();
+ /// let (mut producer, mut consumer) = queue.split();
+ /// assert!(consumer.is_empty());
+ /// ```
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.inner.is_empty()
+ }
+
+ /// Returns the maximum number of elements the queue can hold
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+
+ /// Returns the item in the front of the queue without dequeuing, or `None` if the queue is
+ /// empty
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use heapless::spsc::Queue;
+ ///
+ /// let mut queue: Queue = Queue::new();
+ /// let (mut producer, mut consumer) = queue.split();
+ /// assert_eq!(None, consumer.peek());
+ /// producer.enqueue(1);
+ /// assert_eq!(Some(&1), consumer.peek());
+ /// assert_eq!(Some(1), consumer.dequeue());
+ /// assert_eq!(None, consumer.peek());
+ /// ```
+ #[inline]
+ pub fn peek(&self) -> Option<&T> {
+ self.inner.peek()
+ }
+}
+
+impl<'a, T, const N: usize> Producer<'a, T, N> {
+ /// Adds an `item` to the end of the queue, returns back the `item` if the queue is full
+ #[inline]
+ pub fn enqueue(&mut self, val: T) -> Result<(), T> {
+ self.inner.enqueue(val)
+ }
+
+ /// Adds an `item` to the end of the queue, without checking if the queue is full
+ ///
+ /// # Safety
+ ///
+ /// See [`Queue::enqueue_unchecked`]
+ #[inline]
+ pub unsafe fn enqueue_unchecked(&mut self, val: T) {
+ self.inner.enqueue_unchecked(val)
+ }
+
+ /// Returns if there is any space to enqueue a new item. When this returns true, at
+ /// least the first subsequent enqueue will succeed.
+ #[inline]
+ pub fn ready(&self) -> bool {
+ self.inner.ready()
+ }
+
+ /// Returns the number of elements in the queue
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ /// Returns true if the queue is empty
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use heapless::spsc::Queue;
+ ///
+ /// let mut queue: Queue = Queue::new();
+ /// let (mut producer, mut consumer) = queue.split();
+ /// assert!(producer.is_empty());
+ /// ```
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.inner.is_empty()
+ }
+
+ /// Returns the maximum number of elements the queue can hold
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+}
+
+/// A queue "consumer"; it can dequeue items from the queue
+/// NOTE the consumer semantically owns the `head` pointer of the queue
+pub struct ConsumerView<'a, T> {
+ rb: &'a QueueView,
+}
+
+unsafe impl<'a, T> Send for ConsumerView<'a, T> where T: Send {}
+
+/// A queue "producer"; it can enqueue items into the queue
+/// NOTE the producer semantically owns the `tail` pointer of the queue
+pub struct ProducerView<'a, T> {
+ rb: &'a QueueView,
+}
+
+unsafe impl<'a, T> Send for ProducerView<'a, T> where T: Send {}
+
+impl<'a, T> ConsumerView<'a, T> {
/// Returns the item in the front of the queue, or `None` if the queue is empty
#[inline]
pub fn dequeue(&mut self) -> Option {
@@ -575,7 +1042,7 @@ impl<'a, T, const N: usize> Consumer<'a, T, N> {
}
}
-impl<'a, T, const N: usize> Producer<'a, T, N> {
+impl<'a, T> ProducerView<'a, T> {
/// Adds an `item` to the end of the queue, returns back the `item` if the queue is full
#[inline]
pub fn enqueue(&mut self, val: T) -> Result<(), T> {
diff --git a/src/vec.rs b/src/vec.rs
index f7c3efbb66..1db505bb8f 100644
--- a/src/vec.rs
+++ b/src/vec.rs
@@ -5,34 +5,37 @@ use core::{
ops, ptr, slice,
};
-/// Workaround forbidden specialization of Drop
-pub trait VecDrop {
- // SAFETY: drop_with_len will be called to call drop in place the first `len` elements of the buffer.
- // Only the Owned buffer (`[MaybeUninit; N]`) must drop the items
- // and the view (`[MaybeUninit]`) drops nothing.
- // `drop_with_len `assumes that the buffer can contain `len` elements.
- unsafe fn drop_with_len(&mut self, len: usize);
+pub trait VecBuffer {
+ type T;
+
+ fn as_vecview(vec: &VecInner) -> &VecView;
+ fn as_mut_vecview(vec: &mut VecInner) -> &mut VecView;
}
-impl VecDrop for [MaybeUninit] {
- unsafe fn drop_with_len(&mut self, _len: usize) {
- // Case of a view, drop does nothing
+impl VecBuffer for [MaybeUninit; N] {
+ type T = T;
+
+ fn as_vecview(vec: &VecInner) -> &VecView {
+ vec
+ }
+ fn as_mut_vecview(vec: &mut VecInner) -> &mut VecView {
+ vec
}
}
-impl VecDrop for [MaybeUninit; N] {
- unsafe fn drop_with_len(&mut self, len: usize) {
- // NOTE(unsafe) avoid bound checks in the slicing operation
- // &mut buffer[..len]
- // SAFETY: buffer[..len] must be valid to drop given the safety requirement of the trait definition.
- let mut_slice = slice::from_raw_parts_mut(self.as_mut_ptr() as *mut T, len);
- // We drop each element used in the vector by turning into a `&mut [T]`.
- ptr::drop_in_place(mut_slice);
+impl VecBuffer for [MaybeUninit] {
+ type T = T;
+
+ fn as_vecview(vec: &VecInner) -> &VecView {
+ vec
+ }
+ fn as_mut_vecview(vec: &mut VecInner) -> &mut VecView {
+ vec
}
}
/// This is private API and should not be used
-pub struct VecInner {
+pub struct VecInner {
len: usize,
buffer: B,
}
@@ -1572,10 +1575,12 @@ impl From<[T; M]> for Vec {
}
}
-impl Drop for VecInner {
+impl Drop for VecInner {
fn drop(&mut self) {
+ let mut_slice = VecBuffer::as_mut_vecview(self).as_mut_slice();
+ // We drop each element used in the vector by turning into a `&mut [T]`.
// SAFETY: the buffer contains initialized data for the range 0..self.len
- unsafe { self.buffer.drop_with_len(self.len) }
+ unsafe { ptr::drop_in_place(mut_slice) }
}
}
@@ -1953,7 +1958,7 @@ mod tests {
use static_assertions::assert_not_impl_any;
- use crate::Vec;
+ use super::{Vec, VecView};
// Ensure a `Vec` containing `!Send` values stays `!Send` itself.
assert_not_impl_any!(Vec<*const (), 4>: Send);
@@ -2014,6 +2019,33 @@ mod tests {
assert_eq!(Droppable::count(), 0);
}
+ #[test]
+ fn drop_vecview() {
+ droppable!();
+
+ {
+ let v: Vec = Vec::new();
+ let mut v: Box> = Box::new(v);
+ v.push(Droppable::new()).ok().unwrap();
+ v.push(Droppable::new()).ok().unwrap();
+ assert_eq!(Droppable::count(), 2);
+ v.pop().unwrap();
+ assert_eq!(Droppable::count(), 1);
+ }
+
+ assert_eq!(Droppable::count(), 0);
+
+ {
+ let v: Vec = Vec::new();
+ let mut v: Box> = Box::new(v);
+ v.push(Droppable::new()).ok().unwrap();
+ v.push(Droppable::new()).ok().unwrap();
+ assert_eq!(Droppable::count(), 2);
+ }
+
+ assert_eq!(Droppable::count(), 0);
+ }
+
#[test]
fn eq() {
let mut xs: Vec = Vec::new();