From 8b29027e185fe89581e7f9f83433fdacb50395cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 11:54:53 +0200 Subject: [PATCH 1/7] Implement binaryheapview --- src/binary_heap.rs | 408 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 403 insertions(+), 5 deletions(-) diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 8bd740845e..7c91c1d9f0 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,7 +45,14 @@ impl Kind for Max { /// Sealed traits mod private { + use core::marker::PhantomData; + pub trait Sealed {} + + pub struct BinaryHeapInner { + pub(crate) _kind: PhantomData, + pub(crate) data: B, + } } impl private::Sealed for Max {} @@ -97,10 +104,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::{BinaryHeapView, BinaryHeap, Max}; +/// +/// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); +/// let mut 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 +175,14 @@ impl BinaryHeap { data: Vec::new(), } } + + pub fn as_view(&self) -> &BinaryHeapView { + self + } + + pub fn as_mut_view(&self) -> &BinaryHeapView { + self + } } impl BinaryHeap @@ -379,6 +440,256 @@ where } } +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, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// heap.push(1).unwrap(); + /// heap.push(3).unwrap(); + /// + /// assert!(!heap.is_empty()); + /// + /// heap.clear(); + /// + /// assert!(heap.is_empty()); + /// ``` + pub fn clear(&mut self) { + self.data.clear() + } + + /// Returns the length of the binary heap. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// heap.push(1).unwrap(); + /// heap.push(3).unwrap(); + /// + /// assert_eq!(heap.len(), 2); + /// ``` + pub fn len(&self) -> usize { + self.data.len() + } + + /// Checks if the binary heap is empty. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// + /// assert!(heap.is_empty()); + /// + /// heap.push(3).unwrap(); + /// heap.push(5).unwrap(); + /// heap.push(1).unwrap(); + /// + /// assert!(!heap.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, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// heap.push(1).unwrap(); + /// heap.push(2).unwrap(); + /// heap.push(3).unwrap(); + /// heap.push(4).unwrap(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order + /// for x in heap.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, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// assert_eq!(heap.peek(), None); + /// + /// heap.push(1).unwrap(); + /// heap.push(5).unwrap(); + /// heap.push(2).unwrap(); + /// assert_eq!(heap.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, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// assert!(heap.peek_mut().is_none()); + /// + /// heap.push(1); + /// heap.push(5); + /// heap.push(2); + /// { + /// let mut val = heap.peek_mut().unwrap(); + /// *val = 0; + /// } + /// + /// assert_eq!(heap.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, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// heap.push(1).unwrap(); + /// heap.push(3).unwrap(); + /// + /// assert_eq!(heap.pop(), Some(3)); + /// assert_eq!(heap.pop(), Some(1)); + /// assert_eq!(heap.pop(), None); + /// ``` + pub fn pop(&mut self) -> Option { + if self.is_empty() { + None + } else { + Some(unsafe { self.pop_unchecked() }) + } + } + + /// 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 { + let mut item = self.data.pop_unchecked(); + + if !self.is_empty() { + mem::swap(&mut item, self.data.as_mut_slice().get_unchecked_mut(0)); + self.sift_down_to_bottom(0); + } + item + } + + /// 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> { + if self.data.is_full() { + return Err(item); + } + + unsafe { self.push_unchecked(item) } + Ok(()) + } + + /// 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) { + let old_len = self.len(); + self.data.push_unchecked(item); + self.sift_up(0, old_len); + } + + /* Private API */ + fn sift_down_to_bottom(&mut self, mut pos: usize) { + let end = self.len(); + let start = pos; + unsafe { + let mut hole = Hole::new(self.data.as_mut_slice(), pos); + let mut child = 2 * pos + 1; + while child < end { + let right = child + 1; + // compare with the greater of the two children + if right < end && hole.get(child).cmp(hole.get(right)) != K::ordering() { + child = right; + } + hole.move_to(child); + child = 2 * hole.pos() + 1; + } + pos = hole.pos; + } + self.sift_up(start, pos); + } + + fn sift_up(&mut self, start: usize, pos: usize) -> usize { + unsafe { + // Take out the value at `pos` and create a hole. + let mut hole = Hole::new(self.data.as_mut_slice(), pos); + + while hole.pos() > start { + let parent = (hole.pos() - 1) / 2; + if hole.element().cmp(hole.get(parent)) != K::ordering() { + break; + } + hole.move_to(parent); + } + hole.pos() + } + } +} + /// Hole represents a hole in a slice i.e. an index without valid value /// (because it was moved from or duplicated). /// In drop, `Hole` will restore the slice by filling the hole @@ -505,6 +816,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 +915,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 +942,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() } From 76bb5756e5f4585844383f428fbb04e98819218e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 12:08:11 +0200 Subject: [PATCH 2/7] Forward BinaryHeap implementations to heapview --- src/binary_heap.rs | 183 ++++++++++++++++++--------------------------- src/lib.rs | 2 +- 2 files changed, 73 insertions(+), 112 deletions(-) diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 7c91c1d9f0..76a2b15e37 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -115,7 +115,7 @@ pub type BinaryHeap = private::BinaryHeapInner = BinaryHeap::new(); /// let mut heap_view: &mut BinaryHeapView<_, Max> = &mut heap; @@ -180,7 +180,7 @@ impl BinaryHeap { self } - pub fn as_mut_view(&self) -> &BinaryHeapView { + pub fn as_mut_view(&mut self) -> &mut BinaryHeapView { self } } @@ -193,7 +193,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. @@ -212,7 +212,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. @@ -227,7 +227,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. @@ -246,7 +246,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. @@ -266,7 +266,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. @@ -274,7 +274,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 @@ -292,7 +292,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 @@ -322,6 +322,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 { @@ -347,24 +348,14 @@ where /// assert_eq!(heap.pop(), None); /// ``` pub fn pop(&mut self) -> Option { - if self.is_empty() { - None - } else { - Some(unsafe { self.pop_unchecked() }) - } + 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 { - let mut item = self.data.pop_unchecked(); - - if !self.is_empty() { - mem::swap(&mut item, self.data.as_mut_slice().get_unchecked_mut(0)); - self.sift_down_to_bottom(0); - } - item + self.as_mut_view().pop_unchecked() } /// Pushes an item onto the binary heap. @@ -381,20 +372,13 @@ where /// assert_eq!(heap.peek(), Some(&5)); /// ``` pub fn push(&mut self, item: T) -> Result<(), T> { - if self.data.is_full() { - return Err(item); - } - - unsafe { self.push_unchecked(item) } - Ok(()) + 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) { - let old_len = self.len(); - self.data.push_unchecked(item); - self.sift_up(0, old_len); + self.as_mut_view().push_unchecked(item) } /// Returns the underlying `Vec`. Order is arbitrary and time is *O*(1). @@ -403,40 +387,8 @@ where } /* Private API */ - fn sift_down_to_bottom(&mut self, mut pos: usize) { - let end = self.len(); - let start = pos; - unsafe { - let mut hole = Hole::new(self.data.as_mut_slice(), pos); - let mut child = 2 * pos + 1; - while child < end { - let right = child + 1; - // compare with the greater of the two children - if right < end && hole.get(child).cmp(hole.get(right)) != K::ordering() { - child = right; - } - hole.move_to(child); - child = 2 * hole.pos() + 1; - } - pos = hole.pos; - } - self.sift_up(start, pos); - } - - fn sift_up(&mut self, start: usize, pos: usize) -> usize { - unsafe { - // Take out the value at `pos` and create a hole. - let mut hole = Hole::new(self.data.as_mut_slice(), pos); - - while hole.pos() > start { - let parent = (hole.pos() - 1) / 2; - if hole.element().cmp(hole.get(parent)) != K::ordering() { - break; - } - hole.move_to(parent); - } - hole.pos() - } + fn sift_down_to_bottom(&mut self, pos: usize) { + self.as_mut_view().sift_down_to_bottom(pos) } } @@ -454,17 +406,19 @@ where /// Drops all items from 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(1).unwrap(); - /// heap.push(3).unwrap(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; /// - /// assert!(!heap.is_empty()); + /// heap_view.push(1).unwrap(); + /// heap_view.push(3).unwrap(); /// - /// heap.clear(); + /// assert!(!heap_view.is_empty()); /// - /// assert!(heap.is_empty()); + /// heap_view.clear(); + /// + /// assert!(heap_view.is_empty()); /// ``` pub fn clear(&mut self) { self.data.clear() @@ -473,13 +427,14 @@ where /// Returns the length of 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(1).unwrap(); - /// heap.push(3).unwrap(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// heap_view.push(1).unwrap(); + /// heap_view.push(3).unwrap(); /// - /// assert_eq!(heap.len(), 2); + /// assert_eq!(heap_view.len(), 2); /// ``` pub fn len(&self) -> usize { self.data.len() @@ -488,17 +443,18 @@ where /// Checks if the binary heap is empty. /// /// ``` - /// use heapless::binary_heap::{BinaryHeap, Max}; + /// 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.is_empty()); + /// assert!(heap_view.is_empty()); /// - /// heap.push(3).unwrap(); - /// heap.push(5).unwrap(); - /// heap.push(1).unwrap(); + /// heap_view.push(3).unwrap(); + /// heap_view.push(5).unwrap(); + /// heap_view.push(1).unwrap(); /// - /// assert!(!heap.is_empty()); + /// assert!(!heap_view.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.len() == 0 @@ -507,16 +463,17 @@ where /// Returns an iterator visiting all values in the underlying vector, in arbitrary order. /// /// ``` - /// use heapless::binary_heap::{BinaryHeap, Max}; + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; /// /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); - /// heap.push(1).unwrap(); - /// heap.push(2).unwrap(); - /// heap.push(3).unwrap(); - /// heap.push(4).unwrap(); + /// 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.iter() { + /// for x in heap_view.iter() { /// println!("{}", x); /// } /// ``` @@ -536,15 +493,16 @@ where /// None if it is empty. /// /// ``` - /// use heapless::binary_heap::{BinaryHeap, Max}; + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; /// /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); - /// assert_eq!(heap.peek(), None); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// assert_eq!(heap_view.peek(), None); /// - /// heap.push(1).unwrap(); - /// heap.push(5).unwrap(); - /// heap.push(2).unwrap(); - /// assert_eq!(heap.peek(), Some(&5)); + /// 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() @@ -561,20 +519,21 @@ where /// Basic usage: /// /// ``` - /// use heapless::binary_heap::{BinaryHeap, Max}; + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; /// /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); - /// assert!(heap.peek_mut().is_none()); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// assert!(heap_view.peek_mut().is_none()); /// - /// heap.push(1); - /// heap.push(5); - /// heap.push(2); + /// heap_view.push(1); + /// heap_view.push(5); + /// heap_view.push(2); /// { - /// let mut val = heap.peek_mut().unwrap(); + /// let mut val = heap_view.peek_mut().unwrap(); /// *val = 0; /// } /// - /// assert_eq!(heap.peek(), Some(&2)); + /// assert_eq!(heap_view.peek(), Some(&2)); /// ``` pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { @@ -591,15 +550,16 @@ where /// returns it, or None if it is empty. /// /// ``` - /// use heapless::binary_heap::{BinaryHeap, Max}; + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; /// /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); - /// heap.push(1).unwrap(); - /// heap.push(3).unwrap(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// heap_view.push(1).unwrap(); + /// heap_view.push(3).unwrap(); /// - /// assert_eq!(heap.pop(), Some(3)); - /// assert_eq!(heap.pop(), Some(1)); - /// assert_eq!(heap.pop(), None); + /// 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() { @@ -625,15 +585,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() { 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::{ From 2fa757a948d730665324ed3790aedf141957fb9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 12:09:07 +0200 Subject: [PATCH 3/7] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) 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 From ff118e819811641ff5ee12f50d66493479affd9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 12:11:52 +0200 Subject: [PATCH 4/7] Implement Serialize for BinaryHeapView --- src/ser.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 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, From 1c651dd57450dcc9b965eb72a4d11d8e34faebc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 13:39:01 +0200 Subject: [PATCH 5/7] Fix docs --- src/binary_heap.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 76a2b15e37..d43675492b 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -55,6 +55,13 @@ mod private { } } +// 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 {} From f81f497efe721d11f6f582ad471283521b8c70a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 13:50:25 +0200 Subject: [PATCH 6/7] Add missing documentation --- src/binary_heap.rs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/binary_heap.rs b/src/binary_heap.rs index d43675492b..6cd604ef27 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -125,7 +125,7 @@ pub type BinaryHeap = private::BinaryHeapInner = BinaryHeap::new(); -/// let mut heap_view: &mut BinaryHeapView<_, Max> = &mut heap; +/// 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. @@ -183,10 +183,44 @@ impl BinaryHeap { } } + /// 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 } From 1c68ada699fb58f6fb49224da8977ef911e232c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jun 2024 13:57:17 +0200 Subject: [PATCH 7/7] Add missing documentation This documentation is not actually generated even though not having it triggers the lint --- src/binary_heap.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 6cd604ef27..e891bff11d 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -49,6 +49,7 @@ mod private { pub trait Sealed {} + ///
This is private API and should not be used
pub struct BinaryHeapInner { pub(crate) _kind: PhantomData, pub(crate) data: B,