Skip to content

Commit

Permalink
Re-introduce covariance for containers
Browse files Browse the repository at this point in the history
  • Loading branch information
sosthene-nitrokey committed Oct 8, 2024
1 parent 69add42 commit b862172
Show file tree
Hide file tree
Showing 10 changed files with 504 additions and 199 deletions.
44 changes: 25 additions & 19 deletions src/binary_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ use core::{
ptr, slice,
};

use crate::{
storage::{OwnedStorage, Storage, ViewStorage},
vec::{Vec, VecInner},
};
use crate::vec::{OwnedVecStorage, Vec, VecInner, VecStorage, ViewVecStorage};

/// Min-heap
pub enum Min {}
Expand Down Expand Up @@ -54,11 +51,11 @@ mod private {
impl private::Sealed for Max {}
impl private::Sealed for Min {}

/// Base struct for [`BinaryHeap`] and [`BinaryHeapView`], generic over the [`Storage`].
/// Base struct for [`BinaryHeap`] and [`BinaryHeapView`], generic over the [`VecStorage`].
///
/// In most cases you should use [`BinaryHeap`] or [`BinaryHeapView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct BinaryHeapInner<T, K, S: Storage> {
pub struct BinaryHeapInner<T, K, S: VecStorage<T> + ?Sized> {
pub(crate) _kind: PhantomData<K>,
pub(crate) data: VecInner<T, S>,
}
Expand Down Expand Up @@ -109,7 +106,7 @@ pub struct BinaryHeapInner<T, K, S: Storage> {
/// // The heap should now be empty.
/// assert!(heap.is_empty())
/// ```
pub type BinaryHeap<T, K, const N: usize> = BinaryHeapInner<T, K, OwnedStorage<N>>;
pub type BinaryHeap<T, K, const N: usize> = BinaryHeapInner<T, K, OwnedVecStorage<T, N>>;

/// A priority queue implemented with a binary heap.
///
Expand Down Expand Up @@ -158,7 +155,7 @@ pub type BinaryHeap<T, K, const N: usize> = BinaryHeapInner<T, K, OwnedStorage<N
/// // The heap should now be empty.
/// assert!(heap.is_empty())
/// ```
pub type BinaryHeapView<T, K> = BinaryHeapInner<T, K, ViewStorage>;
pub type BinaryHeapView<T, K> = BinaryHeapInner<T, K, ViewVecStorage<T>>;

impl<T, K, const N: usize> BinaryHeap<T, K, N> {
/* Constructors */
Expand Down Expand Up @@ -198,7 +195,7 @@ impl<T, K, const N: usize> BinaryHeap<T, K, N> {
}
}

impl<T, K, S: Storage> BinaryHeapInner<T, K, S>
impl<T, K, S: VecStorage<T> + ?Sized> BinaryHeapInner<T, K, S>
where
T: Ord,
K: Kind,
Expand Down Expand Up @@ -539,7 +536,7 @@ pub struct PeekMutInner<'a, T, K, S>
where
T: Ord,
K: Kind,
S: Storage,
S: VecStorage<T> + ?Sized,
{
heap: &'a mut BinaryHeapInner<T, K, S>,
sift: bool,
Expand All @@ -550,20 +547,20 @@ where
///
/// This `struct` is created by [`BinaryHeap::peek_mut`].
/// See its documentation for more.
pub type PeekMut<'a, T, K, const N: usize> = PeekMutInner<'a, T, K, OwnedStorage<N>>;
pub type PeekMut<'a, T, K, const N: usize> = PeekMutInner<'a, T, K, OwnedVecStorage<T, N>>;

/// Structure wrapping a mutable reference to the greatest item on a
/// `BinaryHeap`.
///
/// This `struct` is created by [`BinaryHeapView::peek_mut`].
/// See its documentation for more.
pub type PeekMutView<'a, T, K> = PeekMutInner<'a, T, K, ViewStorage>;
pub type PeekMutView<'a, T, K> = PeekMutInner<'a, T, K, ViewVecStorage<T>>;

impl<T, K, S> Drop for PeekMutInner<'_, T, K, S>
where
T: Ord,
K: Kind,
S: Storage,
S: VecStorage<T> + ?Sized,
{
fn drop(&mut self) {
if self.sift {
Expand All @@ -576,7 +573,7 @@ impl<T, K, S> Deref for PeekMutInner<'_, T, K, S>
where
T: Ord,
K: Kind,
S: Storage,
S: VecStorage<T> + ?Sized,
{
type Target = T;
fn deref(&self) -> &T {
Expand All @@ -590,7 +587,7 @@ impl<T, K, S> DerefMut for PeekMutInner<'_, T, K, S>
where
T: Ord,
K: Kind,
S: Storage,
S: VecStorage<T> + ?Sized,
{
fn deref_mut(&mut self) -> &mut T {
debug_assert!(!self.heap.is_empty());
Expand All @@ -603,7 +600,7 @@ impl<'a, T, K, S> PeekMutInner<'a, T, K, S>
where
T: Ord,
K: Kind,
S: Storage,
S: VecStorage<T> + ?Sized,
{
/// Removes the peeked value from the heap and returns it.
pub fn pop(mut this: PeekMutInner<'a, T, K, S>) -> T {
Expand Down Expand Up @@ -651,7 +648,7 @@ impl<T, K, S> fmt::Debug for BinaryHeapInner<T, K, S>
where
K: Kind,
T: Ord + fmt::Debug,
S: Storage,
S: VecStorage<T> + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
Expand All @@ -662,7 +659,7 @@ impl<'a, T, K, S> IntoIterator for &'a BinaryHeapInner<T, K, S>
where
K: Kind,
T: Ord,
S: Storage,
S: VecStorage<T> + ?Sized,
{
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
Expand All @@ -676,7 +673,7 @@ where
mod tests {
use static_assertions::assert_not_impl_any;

use super::{BinaryHeap, Max, Min};
use super::{BinaryHeap, BinaryHeapView, Max, Min};

// Ensure a `BinaryHeap` containing `!Send` values stays `!Send` itself.
assert_not_impl_any!(BinaryHeap<*const (), Max, 4>: Send);
Expand Down Expand Up @@ -849,4 +846,13 @@ mod tests {
assert_eq!(heap.pop(), Some(1));
assert_eq!(heap.pop(), None);
}

fn _test_variance<'a: 'b, 'b>(x: BinaryHeap<&'a (), Max, 42>) -> BinaryHeap<&'b (), Max, 42> {
x
}
fn _test_variance_view<'a: 'b, 'b, 'c>(
x: &'c BinaryHeapView<&'a (), Max>,
) -> &'c BinaryHeapView<&'b (), Max> {
x
}
}
9 changes: 6 additions & 3 deletions src/defmt.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
//! Defmt implementations for heapless types

use crate::{storage::Storage, string::StringInner, vec::VecInner};
use crate::{
string::StringInner,
vec::{VecInner, VecStorage},
};
use defmt::Formatter;

impl<T, S: Storage> defmt::Format for VecInner<T, S>
impl<T, S: VecStorage<T> + ?Sized> defmt::Format for VecInner<T, S>
where
T: defmt::Format,
{
Expand All @@ -12,7 +15,7 @@ where
}
}

impl<S: Storage> defmt::Format for StringInner<S>
impl<S: VecStorage<u8> + ?Sized> defmt::Format for StringInner<S>
where
u8: defmt::Format,
{
Expand Down
35 changes: 20 additions & 15 deletions src/deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,21 @@
//! }
//! ```

use core::borrow::{Borrow, BorrowMut};
use core::fmt;
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::{ptr, slice};

use crate::storage::{OwnedStorage, Storage, ViewStorage};
use crate::vec::{OwnedVecStorage, VecStorage, VecStorageInner, ViewVecStorage};

/// Base struct for [`Deque`] and [`DequeView`], generic over the [`Storage`].
/// Base struct for [`Deque`] and [`DequeView`], generic over the [`VecStorage`].
///
/// In most cases you should use [`Deque`] or [`DequeView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct DequeInner<T, S: Storage> {
pub struct DequeInner<T, S: VecStorage<T> + ?Sized> {
// This phantomdata is required because otherwise rustc thinks that `T` is not used
phantom: PhantomData<T>,
/// Front index. Always 0..=(N-1)
front: usize,
/// Back index. Always 0..=(N-1).
Expand All @@ -54,7 +56,7 @@ pub struct DequeInner<T, S: Storage> {
/// Used to distinguish "empty" and "full" cases when `front == back`.
/// May only be `true` if `front == back`, always `false` otherwise.
full: bool,
buffer: S::Buffer<MaybeUninit<T>>,
buffer: S,
}

/// A fixed capacity double-ended queue.
Expand Down Expand Up @@ -91,7 +93,7 @@ pub struct DequeInner<T, S: Storage> {
/// println!("{}", x);
/// }
/// ```
pub type Deque<T, const N: usize> = DequeInner<T, OwnedStorage<N>>;
pub type Deque<T, const N: usize> = DequeInner<T, OwnedVecStorage<T, N>>;

/// A double-ended queue with dynamic capacity.
///
Expand Down Expand Up @@ -130,7 +132,7 @@ pub type Deque<T, const N: usize> = DequeInner<T, OwnedStorage<N>>;
/// println!("{}", x);
/// }
/// ```
pub type DequeView<T> = DequeInner<T, ViewStorage>;
pub type DequeView<T> = DequeInner<T, ViewVecStorage<T>>;

impl<T, const N: usize> Deque<T, N> {
const INIT: MaybeUninit<T> = MaybeUninit::uninit();
Expand All @@ -153,7 +155,10 @@ impl<T, const N: usize> Deque<T, N> {
crate::sealed::greater_than_0::<N>();

Self {
buffer: [Self::INIT; N],
phantom: PhantomData,
buffer: VecStorageInner {
buffer: [Self::INIT; N],
},
front: 0,
back: 0,
full: false,
Expand Down Expand Up @@ -191,7 +196,7 @@ impl<T, const N: usize> Deque<T, N> {
}
}

impl<T, S: Storage> DequeInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
/// Returns the maximum number of elements the deque can hold.
pub fn storage_capacity(&self) -> usize {
self.buffer.borrow().len()
Expand Down Expand Up @@ -794,29 +799,29 @@ impl<T, const N: usize> Default for Deque<T, N> {
}
}

impl<T, S: Storage> Drop for DequeInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> Drop for DequeInner<T, S> {
fn drop(&mut self) {
// safety: `self` is left in an inconsistent state but it doesn't matter since
// it's getting dropped. Nothing should be able to observe `self` after drop.
unsafe { self.drop_contents() }
}
}

impl<T: fmt::Debug, S: Storage> fmt::Debug for DequeInner<T, S> {
impl<T: fmt::Debug, S: VecStorage<T> + ?Sized> fmt::Debug for DequeInner<T, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self).finish()
}
}

/// As with the standard library's `VecDeque`, items are added via `push_back`.
impl<T, S: Storage> Extend<T> for DequeInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> Extend<T> for DequeInner<T, S> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
for item in iter {
self.push_back(item).ok().unwrap();
}
}
}
impl<'a, T: 'a + Copy, S: Storage> Extend<&'a T> for DequeInner<T, S> {
impl<'a, T: 'a + Copy, S: VecStorage<T> + ?Sized> Extend<&'a T> for DequeInner<T, S> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
self.extend(iter.into_iter().copied())
}
Expand Down Expand Up @@ -846,7 +851,7 @@ impl<T, const N: usize> IntoIterator for Deque<T, N> {
}
}

impl<'a, T, S: Storage> IntoIterator for &'a DequeInner<T, S> {
impl<'a, T, S: VecStorage<T> + ?Sized> IntoIterator for &'a DequeInner<T, S> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;

Expand All @@ -855,7 +860,7 @@ impl<'a, T, S: Storage> IntoIterator for &'a DequeInner<T, S> {
}
}

impl<'a, T, S: Storage> IntoIterator for &'a mut DequeInner<T, S> {
impl<'a, T, S: VecStorage<T> + ?Sized> IntoIterator for &'a mut DequeInner<T, S> {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;

Expand Down
Loading

0 comments on commit b862172

Please sign in to comment.