diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0bea10baa6..d1ff1b8500 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 `BinaryHeapView`, the `!Sized` version of `BinaryHeap`.
### Changed
diff --git a/src/binary_heap.rs b/src/binary_heap.rs
index 8bd740845e..e891bff11d 100644
--- a/src/binary_heap.rs
+++ b/src/binary_heap.rs
@@ -17,7 +17,7 @@ use core::{
ptr, slice,
};
-use crate::vec::Vec;
+use crate::{vec::Vec, VecView};
/// Min-heap
pub enum Min {}
@@ -45,9 +45,24 @@ impl Kind for Max {
/// Sealed traits
mod private {
+ use core::marker::PhantomData;
+
pub trait Sealed {}
+
+ ///
This is private API and should not be used
+ pub struct BinaryHeapInner {
+ pub(crate) _kind: PhantomData,
+ pub(crate) data: B,
+ }
}
+// Workaround https://github.com/rust-lang/rust/issues/119015. This is required so that the methods on `VecView` and `Vec` are properly documented.
+// cfg(doc) prevents `VecInner` 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::BinaryHeapInner as _;
+
impl private::Sealed for Max {}
impl private::Sealed for Min {}
@@ -97,10 +112,56 @@ impl private::Sealed for Min {}
/// // The heap should now be empty.
/// assert!(heap.is_empty())
/// ```
-pub struct BinaryHeap {
- pub(crate) _kind: PhantomData,
- pub(crate) data: Vec,
-}
+pub type BinaryHeap = private::BinaryHeapInner>;
+
+/// A priority queue implemented with a binary heap.
+///
+/// This can be either a min-heap or a max-heap.
+///
+/// It is a logic error for an item to be modified in such a way that the item's ordering relative
+/// to any other item, as determined by the `Ord` trait, changes while it is in the heap. This is
+/// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
+///
+/// ```
+/// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
+///
+/// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+/// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+///
+/// // We can use peek to look at the next item in the heap_view. In this case,
+/// // there's no items in there yet so we get None.
+/// assert_eq!(heap_view.peek(), None);
+///
+/// // Let's add some scores...
+/// heap_view.push(1).unwrap();
+/// heap_view.push(5).unwrap();
+/// heap_view.push(2).unwrap();
+///
+/// // Now peek shows the most important item in the heap.
+/// assert_eq!(heap_view.peek(), Some(&5));
+///
+/// // We can check the length of a heap.
+/// assert_eq!(heap_view.len(), 3);
+///
+/// // We can iterate over the items in the heap, although they are returned in
+/// // a random order.
+/// for x in &*heap_view {
+/// println!("{}", x);
+/// }
+///
+/// // If we instead pop these scores, they should come back in order.
+/// assert_eq!(heap_view.pop(), Some(5));
+/// assert_eq!(heap_view.pop(), Some(2));
+/// assert_eq!(heap_view.pop(), Some(1));
+/// assert_eq!(heap_view.pop(), None);
+///
+/// // We can clear the heap of any remaining items.
+/// heap_view.clear();
+///
+/// // The heap_view should now be empty.
+/// assert!(heap_view.is_empty())
+/// ```
+pub type BinaryHeapView = private::BinaryHeapInner>;
impl BinaryHeap {
/* Constructors */
@@ -122,6 +183,48 @@ impl BinaryHeap {
data: Vec::new(),
}
}
+
+ /// Get a reference to the `BinaryHeap`, erasing the `N` const-generic
+ ///
+ /// ```
+ /// # use heapless::{BinaryHeap, BinaryHeapView, binary_heap::Max};
+ ///
+ /// let heap: BinaryHeap = BinaryHeap::new();
+ /// let heap_view: &BinaryHeapView<_, _> = heap.as_view();
+ /// ````
+ ///
+ /// It is often preferable to do the same through type coerction, since `BinaryHeap` implements `Unsize>`:
+ ///
+ /// ```rust
+ /// # use heapless::{BinaryHeap, BinaryHeapView, binary_heap::Max};
+ ///
+ /// let heap: BinaryHeap = BinaryHeap::new();
+ /// let heap_view: &BinaryHeapView<_, _> = &heap;
+ /// ```
+ pub fn as_view(&self) -> &BinaryHeapView {
+ self
+ }
+
+ /// Get a mutable reference to the `BinaryHeap`, erasing the `N` const-generic
+ ///
+ /// ```
+ /// # use heapless::{BinaryHeap, BinaryHeapView, binary_heap::Max};
+ ///
+ /// let mut heap: BinaryHeap = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, _> = heap.as_mut_view();
+ /// ````
+ ///
+ /// It is often preferable to do the same through type coerction, since `BinaryHeap` implements `Unsize>`:
+ ///
+ /// ```rust
+ /// # use heapless::{BinaryHeap, BinaryHeapView, binary_heap::Max};
+ ///
+ /// let mut heap: BinaryHeap = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, _> = &mut heap;
+ /// ```
+ pub fn as_mut_view(&mut self) -> &mut BinaryHeapView {
+ self
+ }
}
impl BinaryHeap
@@ -132,7 +235,7 @@ where
/* Public API */
/// Returns the capacity of the binary heap.
pub fn capacity(&self) -> usize {
- self.data.capacity()
+ self.as_view().capacity()
}
/// Drops all items from the binary heap.
@@ -151,7 +254,7 @@ where
/// assert!(heap.is_empty());
/// ```
pub fn clear(&mut self) {
- self.data.clear()
+ self.as_mut_view().clear()
}
/// Returns the length of the binary heap.
@@ -166,7 +269,7 @@ where
/// assert_eq!(heap.len(), 2);
/// ```
pub fn len(&self) -> usize {
- self.data.len()
+ self.as_view().len()
}
/// Checks if the binary heap is empty.
@@ -185,7 +288,7 @@ where
/// assert!(!heap.is_empty());
/// ```
pub fn is_empty(&self) -> bool {
- self.len() == 0
+ self.as_view().is_empty()
}
/// Returns an iterator visiting all values in the underlying vector, in arbitrary order.
@@ -205,7 +308,7 @@ where
/// }
/// ```
pub fn iter(&self) -> slice::Iter<'_, T> {
- self.data.as_slice().iter()
+ self.as_view().iter()
}
/// Returns a mutable iterator visiting all values in the underlying vector, in arbitrary order.
@@ -213,7 +316,7 @@ where
/// **WARNING** Mutating the items in the binary heap can leave the heap in an inconsistent
/// state.
pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
- self.data.as_mut_slice().iter_mut()
+ self.as_mut_view().iter_mut()
}
/// Returns the *top* (greatest if max-heap, smallest if min-heap) item in the binary heap, or
@@ -231,7 +334,7 @@ where
/// assert_eq!(heap.peek(), Some(&5));
/// ```
pub fn peek(&self) -> Option<&T> {
- self.data.as_slice().first()
+ self.as_view().peek()
}
/// Returns a mutable reference to the greatest item in the binary heap, or
@@ -261,6 +364,7 @@ where
/// assert_eq!(heap.peek(), Some(&2));
/// ```
pub fn peek_mut(&mut self) -> Option> {
+ // FIXME: return a PeekMutView. Require breaking change
if self.is_empty() {
None
} else {
@@ -285,6 +389,220 @@ where
/// assert_eq!(heap.pop(), Some(1));
/// assert_eq!(heap.pop(), None);
/// ```
+ pub fn pop(&mut self) -> Option {
+ self.as_mut_view().pop()
+ }
+
+ /// Removes the *top* (greatest if max-heap, smallest if min-heap) item from the binary heap and
+ /// returns it, without checking if the binary heap is empty.
+ #[allow(clippy::missing_safety_doc)] // TODO
+ pub unsafe fn pop_unchecked(&mut self) -> T {
+ self.as_mut_view().pop_unchecked()
+ }
+
+ /// Pushes an item onto the binary heap.
+ ///
+ /// ```
+ /// use heapless::binary_heap::{BinaryHeap, Max};
+ ///
+ /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+ /// heap.push(3).unwrap();
+ /// heap.push(5).unwrap();
+ /// heap.push(1).unwrap();
+ ///
+ /// assert_eq!(heap.len(), 3);
+ /// assert_eq!(heap.peek(), Some(&5));
+ /// ```
+ pub fn push(&mut self, item: T) -> Result<(), T> {
+ self.as_mut_view().push(item)
+ }
+
+ /// Pushes an item onto the binary heap without first checking if it's full.
+ #[allow(clippy::missing_safety_doc)] // TODO
+ pub unsafe fn push_unchecked(&mut self, item: T) {
+ self.as_mut_view().push_unchecked(item)
+ }
+
+ /// Returns the underlying `Vec`. Order is arbitrary and time is *O*(1).
+ pub fn into_vec(self) -> Vec {
+ self.data
+ }
+
+ /* Private API */
+ fn sift_down_to_bottom(&mut self, pos: usize) {
+ self.as_mut_view().sift_down_to_bottom(pos)
+ }
+}
+
+impl BinaryHeapView
+where
+ T: Ord,
+ K: Kind,
+{
+ /* Public API */
+ /// Returns the capacity of the binary heap.
+ pub fn capacity(&self) -> usize {
+ self.data.capacity()
+ }
+
+ /// Drops all items from the binary heap.
+ ///
+ /// ```
+ /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
+ ///
+ /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+ ///
+ /// heap_view.push(1).unwrap();
+ /// heap_view.push(3).unwrap();
+ ///
+ /// assert!(!heap_view.is_empty());
+ ///
+ /// heap_view.clear();
+ ///
+ /// assert!(heap_view.is_empty());
+ /// ```
+ pub fn clear(&mut self) {
+ self.data.clear()
+ }
+
+ /// Returns the length of the binary heap.
+ ///
+ /// ```
+ /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
+ ///
+ /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+ /// heap_view.push(1).unwrap();
+ /// heap_view.push(3).unwrap();
+ ///
+ /// assert_eq!(heap_view.len(), 2);
+ /// ```
+ pub fn len(&self) -> usize {
+ self.data.len()
+ }
+
+ /// Checks if the binary heap is empty.
+ ///
+ /// ```
+ /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
+ ///
+ /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+ ///
+ /// assert!(heap_view.is_empty());
+ ///
+ /// heap_view.push(3).unwrap();
+ /// heap_view.push(5).unwrap();
+ /// heap_view.push(1).unwrap();
+ ///
+ /// assert!(!heap_view.is_empty());
+ /// ```
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Returns an iterator visiting all values in the underlying vector, in arbitrary order.
+ ///
+ /// ```
+ /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
+ ///
+ /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+ /// heap_view.push(1).unwrap();
+ /// heap_view.push(2).unwrap();
+ /// heap_view.push(3).unwrap();
+ /// heap_view.push(4).unwrap();
+ ///
+ /// // Print 1, 2, 3, 4 in arbitrary order
+ /// for x in heap_view.iter() {
+ /// println!("{}", x);
+ /// }
+ /// ```
+ pub fn iter(&self) -> slice::Iter<'_, T> {
+ self.data.as_slice().iter()
+ }
+
+ /// Returns a mutable iterator visiting all values in the underlying vector, in arbitrary order.
+ ///
+ /// **WARNING** Mutating the items in the binary heap can leave the heap in an inconsistent
+ /// state.
+ pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
+ self.data.as_mut_slice().iter_mut()
+ }
+
+ /// Returns the *top* (greatest if max-heap, smallest if min-heap) item in the binary heap, or
+ /// None if it is empty.
+ ///
+ /// ```
+ /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
+ ///
+ /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+ /// assert_eq!(heap_view.peek(), None);
+ ///
+ /// heap_view.push(1).unwrap();
+ /// heap_view.push(5).unwrap();
+ /// heap_view.push(2).unwrap();
+ /// assert_eq!(heap_view.peek(), Some(&5));
+ /// ```
+ pub fn peek(&self) -> Option<&T> {
+ self.data.as_slice().first()
+ }
+
+ /// Returns a mutable reference to the greatest item in the binary heap, or
+ /// `None` if it is empty.
+ ///
+ /// Note: If the `PeekMut` value is leaked, the heap may be in an
+ /// inconsistent state.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
+ ///
+ /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+ /// assert!(heap_view.peek_mut().is_none());
+ ///
+ /// heap_view.push(1);
+ /// heap_view.push(5);
+ /// heap_view.push(2);
+ /// {
+ /// let mut val = heap_view.peek_mut().unwrap();
+ /// *val = 0;
+ /// }
+ ///
+ /// assert_eq!(heap_view.peek(), Some(&2));
+ /// ```
+ pub fn peek_mut(&mut self) -> Option> {
+ if self.is_empty() {
+ None
+ } else {
+ Some(PeekMutView {
+ heap: self,
+ sift: true,
+ })
+ }
+ }
+
+ /// Removes the *top* (greatest if max-heap, smallest if min-heap) item from the binary heap and
+ /// returns it, or None if it is empty.
+ ///
+ /// ```
+ /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
+ ///
+ /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
+ /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+ /// heap_view.push(1).unwrap();
+ /// heap_view.push(3).unwrap();
+ ///
+ /// assert_eq!(heap_view.pop(), Some(3));
+ /// assert_eq!(heap_view.pop(), Some(1));
+ /// assert_eq!(heap_view.pop(), None);
+ /// ```
pub fn pop(&mut self) -> Option {
if self.is_empty() {
None
@@ -309,15 +627,16 @@ where
/// Pushes an item onto the binary heap.
///
/// ```
- /// use heapless::binary_heap::{BinaryHeap, Max};
+ /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max};
///
/// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new();
- /// heap.push(3).unwrap();
- /// heap.push(5).unwrap();
- /// heap.push(1).unwrap();
+ /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap;
+ /// heap_view.push(3).unwrap();
+ /// heap_view.push(5).unwrap();
+ /// heap_view.push(1).unwrap();
///
- /// assert_eq!(heap.len(), 3);
- /// assert_eq!(heap.peek(), Some(&5));
+ /// assert_eq!(heap_view.len(), 3);
+ /// assert_eq!(heap_view.peek(), Some(&5));
/// ```
pub fn push(&mut self, item: T) -> Result<(), T> {
if self.data.is_full() {
@@ -336,11 +655,6 @@ where
self.sift_up(0, old_len);
}
- /// Returns the underlying `Vec`. Order is arbitrary and time is *O*(1).
- pub fn into_vec(self) -> Vec {
- self.data
- }
-
/* Private API */
fn sift_down_to_bottom(&mut self, mut pos: usize) {
let end = self.len();
@@ -505,6 +819,70 @@ where
}
}
+/// Structure wrapping a mutable reference to the greatest item on a
+/// `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::peek_mut`].
+/// See its documentation for more.
+pub struct PeekMutView<'a, T, K>
+where
+ T: Ord,
+ K: Kind,
+{
+ heap: &'a mut BinaryHeapView,
+ sift: bool,
+}
+
+impl Drop for PeekMutView<'_, T, K>
+where
+ T: Ord,
+ K: Kind,
+{
+ fn drop(&mut self) {
+ if self.sift {
+ self.heap.sift_down_to_bottom(0);
+ }
+ }
+}
+
+impl Deref for PeekMutView<'_, T, K>
+where
+ T: Ord,
+ K: Kind,
+{
+ type Target = T;
+ fn deref(&self) -> &T {
+ debug_assert!(!self.heap.is_empty());
+ // SAFE: PeekMut is only instantiated for non-empty heaps
+ unsafe { self.heap.data.as_slice().get_unchecked(0) }
+ }
+}
+
+impl DerefMut for PeekMutView<'_, T, K>
+where
+ T: Ord,
+ K: Kind,
+{
+ fn deref_mut(&mut self) -> &mut T {
+ debug_assert!(!self.heap.is_empty());
+ // SAFE: PeekMut is only instantiated for non-empty heaps
+ unsafe { self.heap.data.as_mut_slice().get_unchecked_mut(0) }
+ }
+}
+
+impl<'a, T, K> PeekMutView<'a, T, K>
+where
+ T: Ord,
+ K: Kind,
+{
+ /// Removes the peeked value from the heap and returns it.
+ pub fn pop(mut this: PeekMutView<'a, T, K>) -> T {
+ let value = this.heap.pop().unwrap();
+ this.sift = false;
+ value
+ }
+}
+
impl<'a, T> Drop for Hole<'a, T> {
#[inline]
fn drop(&mut self) {
@@ -540,6 +918,16 @@ where
}
impl fmt::Debug for BinaryHeap
+where
+ K: Kind,
+ T: Ord + fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.as_view().fmt(f)
+ }
+}
+
+impl fmt::Debug for BinaryHeapView
where
K: Kind,
T: Ord + fmt::Debug,
@@ -557,6 +945,19 @@ where
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
+ fn into_iter(self) -> Self::IntoIter {
+ self.as_view().into_iter()
+ }
+}
+
+impl<'a, T, K> IntoIterator for &'a BinaryHeapView
+where
+ K: Kind,
+ T: Ord,
+{
+ type Item = &'a T;
+ type IntoIter = slice::Iter<'a, T>;
+
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
diff --git a/src/lib.rs b/src/lib.rs
index b5238c672c..67c18af948 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -85,7 +85,7 @@
feature(integer_atomics)
)]
-pub use binary_heap::BinaryHeap;
+pub use binary_heap::{BinaryHeap, BinaryHeapView};
pub use deque::Deque;
pub use histbuf::{HistoryBuffer, OldestOrdered};
pub use indexmap::{
diff --git a/src/ser.rs b/src/ser.rs
index f929ba8b12..6b14728601 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -1,14 +1,27 @@
use core::hash::{BuildHasher, Hash};
use crate::{
- binary_heap::Kind as BinaryHeapKind, BinaryHeap, Deque, IndexMap, IndexSet, LinearMap, String,
- Vec,
+ binary_heap::Kind as BinaryHeapKind, BinaryHeap, BinaryHeapView, Deque, IndexMap, IndexSet,
+ LinearMap, String, Vec,
};
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
// Sequential containers
impl Serialize for BinaryHeap
+where
+ T: Ord + Serialize,
+ KIND: BinaryHeapKind,
+{
+ fn serialize(&self, serializer: S) -> Result
+ where
+ S: Serializer,
+ {
+ self.as_view().serialize(serializer)
+ }
+}
+
+impl Serialize for BinaryHeapView
where
T: Ord + Serialize,
KIND: BinaryHeapKind,