Merge pull request #502 from Nitrokey/vec-covariance

Re-introduce covariance for containers
This commit is contained in:
Daniel Egger 2025-03-18 19:37:45 +00:00 committed by GitHub
commit 3c97d2f035
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 503 additions and 199 deletions

View File

@ -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 {}
@ -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>,
}
@ -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.
///
@ -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 */
@ -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,
@ -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,
@ -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 {
@ -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 {
@ -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());
@ -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 {
@ -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()
@ -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>;
@ -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);
@ -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
}
}

View File

@ -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,
{
@ -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,
{

View File

@ -33,20 +33,22 @@
//! }
//! ```
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
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).
@ -55,7 +57,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.
@ -92,7 +94,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.
///
@ -131,7 +133,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();
@ -154,7 +156,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,
@ -192,7 +197,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()
@ -866,7 +871,7 @@ 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.
@ -874,21 +879,21 @@ impl<T, S: Storage> Drop for DequeInner<T, S> {
}
}
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())
}
@ -918,7 +923,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>;
@ -927,7 +932,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>;

View File

@ -31,8 +31,6 @@
//! assert_eq!(avg, 4);
//! ```
use core::borrow::Borrow;
use core::borrow::BorrowMut;
use core::fmt;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
@ -40,18 +38,89 @@ use core::ops::Deref;
use core::ptr;
use core::slice;
use crate::storage::OwnedStorage;
use crate::storage::Storage;
use crate::storage::ViewStorage;
mod storage {
use core::mem::MaybeUninit;
/// Base struct for [`HistoryBuffer`] and [`HistoryBufferView`], generic over the [`Storage`].
/// Trait defining how data for a container is stored.
///
/// There's two implementations available:
///
/// - [`OwnedHistBufStorage`]: stores the data in an array `[T; N]` whose size is known at compile time.
/// - [`ViewHistBufStorage`]: stores the data in an unsized `[T]`.
///
/// This allows [`HistoryBuffer`] to be generic over either sized or unsized storage. The [`histbuf`]
/// module contains a [`HistoryBufferInner`] struct that's generic on [`HistBufStorage`],
/// and two type aliases for convenience:
///
/// - [`HistBuf<T, N>`](super::HistoryBuffer) = `HistoryBufferInner<T, OwnedHistBufStorage<T, N>>`
/// - [`HistBufView<T>`](super::HistoryBufferView) = `HistoryBufferInner<T, ViewHistBufStorage<T>>`
///
/// `HistoryBuffer` can be unsized into `HistoryBufferView`, either by unsizing coercions such as `&mut HistoryBuffer -> &mut HistoryBufferView` or
/// `Box<HistoryBuffer> -> Box<HistoryBufferView>`, or explicitly with [`.as_view()`](super::HistoryBuffer::as_view) or [`.as_mut_view()`](super::HistoryBuffer::as_mut_view).
///
/// This trait is sealed, so you cannot implement it for your own types. You can only use
/// the implementations provided by this crate.
///
/// [`HistoryBufferInner`]: super::HistoryBufferInner
/// [`HistoryBuffer`]: super::HistoryBuffer
/// [`HistoryBufferView`]: super::HistoryBufferView
/// [`histbuf`]: super
#[allow(private_bounds)]
pub trait HistBufStorage<T>: HistBufSealedStorage<T> {}
pub trait HistBufSealedStorage<T> {
// part of the sealed trait so that no trait is publicly implemented by `OwnedHistBufStorage` besides `Storage`
fn borrow(&self) -> &[MaybeUninit<T>];
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>];
}
// One sealed layer of indirection to hide the internal details (The MaybeUninit).
pub struct HistBufStorageInner<T: ?Sized> {
pub(crate) buffer: T,
}
/// Implementation of [`HistBufStorage`] that stores the data in an array `[T; N]` whose size is known at compile time.
pub type OwnedHistBufStorage<T, const N: usize> = HistBufStorageInner<[MaybeUninit<T>; N]>;
/// Implementation of [`HistBufStorage`] that stores the data in an unsized `[T]`.
pub type ViewHistBufStorage<T> = HistBufStorageInner<[MaybeUninit<T>]>;
impl<T, const N: usize> HistBufSealedStorage<T> for OwnedHistBufStorage<T, N> {
fn borrow(&self) -> &[MaybeUninit<T>] {
&self.buffer
}
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>] {
&mut self.buffer
}
}
impl<T, const N: usize> HistBufStorage<T> for OwnedHistBufStorage<T, N> {}
impl<T> HistBufSealedStorage<T> for ViewHistBufStorage<T> {
fn borrow(&self) -> &[MaybeUninit<T>] {
&self.buffer
}
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>] {
&mut self.buffer
}
}
impl<T> HistBufStorage<T> for ViewHistBufStorage<T> {}
}
pub use storage::{HistBufStorage, OwnedHistBufStorage, ViewHistBufStorage};
use storage::HistBufStorageInner;
use self::storage::HistBufSealedStorage;
/// Base struct for [`HistoryBuffer`] and [`HistoryBufferView`], generic over the [`HistBufStorage`].
///
/// In most cases you should use [`HistoryBuffer`] or [`HistoryBufferView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct HistoryBufferInner<T, S: Storage> {
pub struct HistoryBufferInner<T, S: HistBufStorage<T> + ?Sized> {
// This phantomdata is required because otherwise rustc thinks that `T` is not used
phantom: PhantomData<T>,
write_at: usize,
filled: bool,
data: S::Buffer<MaybeUninit<T>>,
data: S,
}
/// A "history buffer", similar to a write-only ring buffer of fixed length.
@ -86,7 +155,7 @@ pub struct HistoryBufferInner<T, S: Storage> {
/// let avg = buf.as_slice().iter().sum::<usize>() / buf.len();
/// assert_eq!(avg, 4);
/// ```
pub type HistoryBuffer<T, const N: usize> = HistoryBufferInner<T, OwnedStorage<N>>;
pub type HistoryBuffer<T, const N: usize> = HistoryBufferInner<T, OwnedHistBufStorage<T, N>>;
/// A "view" into a [`HistoryBuffer`]
///
@ -119,7 +188,7 @@ pub type HistoryBuffer<T, const N: usize> = HistoryBufferInner<T, OwnedStorage<N
/// let avg = buf.as_slice().iter().sum::<usize>() / buf.len();
/// assert_eq!(avg, 4);
/// ```
pub type HistoryBufferView<T> = HistoryBufferInner<T, ViewStorage>;
pub type HistoryBufferView<T> = HistoryBufferInner<T, ViewHistBufStorage<T>>;
impl<T, const N: usize> HistoryBuffer<T, N> {
const INIT: MaybeUninit<T> = MaybeUninit::uninit();
@ -143,11 +212,26 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
crate::sealed::greater_than_0::<N>();
Self {
data: [Self::INIT; N],
phantom: PhantomData,
data: HistBufStorageInner {
buffer: [Self::INIT; N],
},
write_at: 0,
filled: false,
}
}
/// Get a reference to the `HistoryBuffer`, erasing the `N` const-generic.
#[inline]
pub const fn as_view(&self) -> &HistoryBufferView<T> {
self
}
/// Get a mutable reference to the `HistoryBuffer`, erasing the `N` const-generic.
#[inline]
pub fn as_mut_view(&mut self) -> &mut HistoryBufferView<T> {
self
}
}
impl<T, const N: usize> HistoryBuffer<T, N>
@ -169,13 +253,16 @@ where
#[inline]
pub fn new_with(t: T) -> Self {
Self {
data: [MaybeUninit::new(t); N],
phantom: PhantomData,
data: HistBufStorageInner {
buffer: [MaybeUninit::new(t); N],
},
write_at: 0,
filled: true,
}
}
}
impl<T: Copy, S: Storage> HistoryBufferInner<T, S> {
impl<T: Copy, S: HistBufStorage<T> + ?Sized> HistoryBufferInner<T, S> {
/// Clears the buffer, replacing every element with the given value.
pub fn clear_with(&mut self, t: T) {
// SAFETY: we reset the values just after
@ -189,7 +276,7 @@ impl<T: Copy, S: Storage> HistoryBufferInner<T, S> {
}
}
impl<T, S: Storage> HistoryBufferInner<T, S> {
impl<T, S: HistBufStorage<T> + ?Sized> HistoryBufferInner<T, S> {
/// Clears the buffer
pub fn clear(&mut self) {
// SAFETY: we reset the values just after
@ -199,7 +286,7 @@ impl<T, S: Storage> HistoryBufferInner<T, S> {
}
}
impl<T, S: Storage> HistoryBufferInner<T, S> {
impl<T, S: HistBufStorage<T> + ?Sized> HistoryBufferInner<T, S> {
unsafe fn drop_contents(&mut self) {
unsafe {
ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
@ -407,7 +494,7 @@ impl<T, S: Storage> HistoryBufferInner<T, S> {
}
}
impl<T, S: Storage> Extend<T> for HistoryBufferInner<T, S> {
impl<T, S: HistBufStorage<T> + ?Sized> Extend<T> for HistoryBufferInner<T, S> {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
@ -418,7 +505,7 @@ impl<T, S: Storage> Extend<T> for HistoryBufferInner<T, S> {
}
}
impl<'a, T, S: Storage> Extend<&'a T> for HistoryBufferInner<T, S>
impl<'a, T, S: HistBufStorage<T> + ?Sized> Extend<&'a T> for HistoryBufferInner<T, S>
where
T: 'a + Clone,
{
@ -436,7 +523,7 @@ where
{
fn clone(&self) -> Self {
let mut ret = Self::new();
for (new, old) in ret.data.iter_mut().zip(self.as_slice()) {
for (new, old) in ret.data.borrow_mut().iter_mut().zip(self.as_slice()) {
new.write(old.clone());
}
ret.filled = self.filled;
@ -445,13 +532,13 @@ where
}
}
impl<T, S: Storage> Drop for HistoryBufferInner<T, S> {
impl<T, S: HistBufStorage<T> + ?Sized> Drop for HistoryBufferInner<T, S> {
fn drop(&mut self) {
unsafe { self.drop_contents() }
}
}
impl<T, S: Storage> Deref for HistoryBufferInner<T, S> {
impl<T, S: HistBufStorage<T> + ?Sized> Deref for HistoryBufferInner<T, S> {
type Target = [T];
fn deref(&self) -> &[T] {
@ -459,14 +546,14 @@ impl<T, S: Storage> Deref for HistoryBufferInner<T, S> {
}
}
impl<T, S: Storage> AsRef<[T]> for HistoryBufferInner<T, S> {
impl<T, S: HistBufStorage<T> + ?Sized> AsRef<[T]> for HistoryBufferInner<T, S> {
#[inline]
fn as_ref(&self) -> &[T] {
self
}
}
impl<T, S: Storage> fmt::Debug for HistoryBufferInner<T, S>
impl<T, S: HistBufStorage<T> + ?Sized> fmt::Debug for HistoryBufferInner<T, S>
where
T: fmt::Debug,
{
@ -481,7 +568,7 @@ impl<T, const N: usize> Default for HistoryBuffer<T, N> {
}
}
impl<T, S: Storage> PartialEq for HistoryBufferInner<T, S>
impl<T, S: HistBufStorage<T> + ?Sized> PartialEq for HistoryBufferInner<T, S>
where
T: PartialEq,
{
@ -490,11 +577,11 @@ where
}
}
/// Base struct for [`OldestOrdered`] and [`OldestOrderedView`], generic over the [`Storage`].
/// Base struct for [`OldestOrdered`] and [`OldestOrderedView`], generic over the [`HistBufStorage`].
///
/// In most cases you should use [`OldestOrdered`] or [`OldestOrderedView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct OldestOrderedInner<'a, T, S: Storage> {
pub struct OldestOrderedInner<'a, T, S: HistBufStorage<T> + ?Sized> {
phantom: PhantomData<S>,
inner: core::iter::Chain<core::slice::Iter<'a, T>, core::slice::Iter<'a, T>>,
}
@ -502,11 +589,12 @@ pub struct OldestOrderedInner<'a, T, S: Storage> {
/// Double ended iterator on the underlying buffer ordered from the oldest data
/// to the newest
/// This type exists for backwards compatibility. It is always better to convert it to an [`OldestOrderedView`] with [`into_view`](OldestOrdered::into_view)
pub type OldestOrdered<'a, T, const N: usize> = OldestOrderedInner<'a, T, OwnedStorage<N>>;
pub type OldestOrdered<'a, T, const N: usize> =
OldestOrderedInner<'a, T, OwnedHistBufStorage<T, N>>;
/// Double ended iterator on the underlying buffer ordered from the oldest data
/// to the newest
pub type OldestOrderedView<'a, T> = OldestOrderedInner<'a, T, ViewStorage>;
pub type OldestOrderedView<'a, T> = OldestOrderedInner<'a, T, ViewHistBufStorage<T>>;
impl<'a, T, const N: usize> OldestOrdered<'a, T, N> {
/// Remove the `N` const-generic parameter from the iterator
@ -534,7 +622,7 @@ impl<'a, T> OldestOrderedView<'a, T> {
}
}
impl<T, S: Storage> Clone for OldestOrderedInner<'_, T, S> {
impl<T, S: HistBufStorage<T> + ?Sized> Clone for OldestOrderedInner<'_, T, S> {
fn clone(&self) -> Self {
Self {
phantom: PhantomData,
@ -543,7 +631,7 @@ impl<T, S: Storage> Clone for OldestOrderedInner<'_, T, S> {
}
}
impl<'a, T, S: Storage> Iterator for OldestOrderedInner<'a, T, S> {
impl<'a, T, S: HistBufStorage<T> + ?Sized> Iterator for OldestOrderedInner<'a, T, S> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
@ -568,7 +656,7 @@ mod tests {
use static_assertions::assert_not_impl_any;
use super::HistoryBuffer;
use super::{HistoryBuffer, HistoryBufferView};
// Ensure a `HistoryBuffer` containing `!Send` values stays `!Send` itself.
assert_not_impl_any!(HistoryBuffer<*const (), 4>: Send);
@ -855,4 +943,13 @@ mod tests {
x.clear();
assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3);
}
fn _test_variance<'a: 'b, 'b>(x: HistoryBuffer<&'a (), 42>) -> HistoryBuffer<&'b (), 42> {
x
}
fn _test_variance_view<'a: 'b, 'b, 'c>(
x: &'c HistoryBufferView<&'a ()>,
) -> &'c HistoryBufferView<&'b ()> {
x
}
}

View File

@ -4,26 +4,22 @@
use core::{borrow::Borrow, fmt, mem, ops, slice};
use crate::{
storage::{OwnedStorage, Storage, ViewStorage},
vec::VecInner,
Vec,
};
use crate::vec::{OwnedVecStorage, Vec, VecInner, VecStorage, ViewVecStorage};
/// Base struct for [`LinearMap`] and [`LinearMapView`]
pub struct LinearMapInner<K, V, S: Storage> {
pub struct LinearMapInner<K, V, S: VecStorage<(K, V)> + ?Sized> {
pub(crate) buffer: VecInner<(K, V), S>,
}
/// A fixed capacity map/dictionary that performs lookups via linear search.
///
/// Note that as this map doesn't use hashing so most operations are *O*(n) instead of *O*(1).
pub type LinearMap<K, V, const N: usize> = LinearMapInner<K, V, OwnedStorage<N>>;
pub type LinearMap<K, V, const N: usize> = LinearMapInner<K, V, OwnedVecStorage<(K, V), N>>;
/// A dynamic capacity map/dictionary that performs lookups via linear search.
///
/// Note that as this map doesn't use hashing so most operations are *O*(n) instead of *O*(1).
pub type LinearMapView<K, V> = LinearMapInner<K, V, ViewStorage>;
pub type LinearMapView<K, V> = LinearMapInner<K, V, ViewVecStorage<(K, V)>>;
impl<K, V, const N: usize> LinearMap<K, V, N> {
/// Creates an empty `LinearMap`.
@ -54,7 +50,7 @@ impl<K, V, const N: usize> LinearMap<K, V, N> {
}
}
impl<K, V, S: Storage> LinearMapInner<K, V, S>
impl<K, V, S: VecStorage<(K, V)> + ?Sized> LinearMapInner<K, V, S>
where
K: Eq,
{
@ -392,7 +388,7 @@ where
}
}
impl<K, V, Q, S: Storage> ops::Index<&Q> for LinearMapInner<K, V, S>
impl<K, V, Q, S: VecStorage<(K, V)> + ?Sized> ops::Index<&'_ Q> for LinearMapInner<K, V, S>
where
K: Borrow<Q> + Eq,
Q: Eq + ?Sized,
@ -404,7 +400,7 @@ where
}
}
impl<K, V, Q, S: Storage> ops::IndexMut<&Q> for LinearMapInner<K, V, S>
impl<K, V, Q, S: VecStorage<(K, V)> + ?Sized> ops::IndexMut<&'_ Q> for LinearMapInner<K, V, S>
where
K: Borrow<Q> + Eq,
Q: Eq + ?Sized,
@ -435,7 +431,7 @@ where
}
}
impl<K, V, S: Storage> fmt::Debug for LinearMapInner<K, V, S>
impl<K, V, S: VecStorage<(K, V)> + ?Sized> fmt::Debug for LinearMapInner<K, V, S>
where
K: Eq + fmt::Debug,
V: fmt::Debug,
@ -493,7 +489,7 @@ where
}
}
impl<'a, K, V, S: Storage> IntoIterator for &'a LinearMapInner<K, V, S>
impl<'a, K, V, S: VecStorage<(K, V)> + ?Sized> IntoIterator for &'a LinearMapInner<K, V, S>
where
K: Eq,
{
@ -540,8 +536,8 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
}
}
impl<K, V, S1: Storage, S2: Storage> PartialEq<LinearMapInner<K, V, S2>>
for LinearMapInner<K, V, S1>
impl<K, V, S1: VecStorage<(K, V)> + ?Sized, S2: VecStorage<(K, V)> + ?Sized>
PartialEq<LinearMapInner<K, V, S2>> for LinearMapInner<K, V, S1>
where
K: Eq,
V: PartialEq,
@ -554,7 +550,7 @@ where
}
}
impl<K, V, S: Storage> Eq for LinearMapInner<K, V, S>
impl<K, V, S: VecStorage<(K, V)> + ?Sized> Eq for LinearMapInner<K, V, S>
where
K: Eq,
V: PartialEq,
@ -565,7 +561,7 @@ where
mod test {
use static_assertions::assert_not_impl_any;
use super::LinearMap;
use super::{LinearMap, LinearMapView};
// Ensure a `LinearMap` containing `!Send` keys stays `!Send` itself.
assert_not_impl_any!(LinearMap<*const (), (), 4>: Send);
@ -640,4 +636,23 @@ mod test {
assert_eq!(v, src.remove(k).unwrap());
}
}
fn _test_variance_value<'a: 'b, 'b>(
x: LinearMap<u32, &'a (), 42>,
) -> LinearMap<u32, &'b (), 42> {
x
}
fn _test_variance_value_view<'a: 'b, 'b, 'c>(
x: &'c LinearMapView<u32, &'a ()>,
) -> &'c LinearMapView<u32, &'b ()> {
x
}
fn _test_variance_key<'a: 'b, 'b>(x: LinearMap<&'a (), u32, 42>) -> LinearMap<&'b (), u32, 42> {
x
}
fn _test_variance_key_view<'a: 'b, 'b, 'c>(
x: &'c LinearMapView<&'a (), u32>,
) -> &'c LinearMapView<&'b (), u32> {
x
}
}

View File

@ -3,11 +3,10 @@ use core::hash::{BuildHasher, Hash};
use crate::{
binary_heap::{BinaryHeapInner, Kind as BinaryHeapKind},
deque::DequeInner,
histbuf::HistoryBufferInner,
histbuf::{HistBufStorage, HistoryBufferInner},
linear_map::LinearMapInner,
storage::Storage,
string::StringInner,
vec::VecInner,
vec::{VecInner, VecStorage},
IndexMap, IndexSet,
};
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
@ -18,7 +17,7 @@ impl<T, KIND, S> Serialize for BinaryHeapInner<T, KIND, S>
where
T: Ord + Serialize,
KIND: BinaryHeapKind,
S: Storage,
S: VecStorage<T> + ?Sized,
{
fn serialize<SER>(&self, serializer: SER) -> Result<SER::Ok, SER::Error>
where
@ -49,7 +48,7 @@ where
}
}
impl<T, St: Storage> Serialize for VecInner<T, St>
impl<T, St: VecStorage<T> + ?Sized> Serialize for VecInner<T, St>
where
T: Serialize,
{
@ -65,7 +64,7 @@ where
}
}
impl<T, S: Storage> Serialize for DequeInner<T, S>
impl<T, S: VecStorage<T> + ?Sized> Serialize for DequeInner<T, S>
where
T: Serialize,
{
@ -81,7 +80,7 @@ where
}
}
impl<T, S: Storage> Serialize for HistoryBufferInner<T, S>
impl<T, S: HistBufStorage<T> + ?Sized> Serialize for HistoryBufferInner<T, S>
where
T: Serialize,
{
@ -117,7 +116,7 @@ where
}
}
impl<K, V, S: Storage> Serialize for LinearMapInner<K, V, S>
impl<K, V, S: VecStorage<(K, V)> + ?Sized> Serialize for LinearMapInner<K, V, S>
where
K: Eq + Serialize,
V: Serialize,
@ -136,7 +135,7 @@ where
// String containers
impl<S: Storage> Serialize for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> Serialize for StringInner<S> {
fn serialize<SER>(&self, serializer: SER) -> Result<SER::Ok, SER::Error>
where
SER: Serializer,

View File

@ -26,7 +26,6 @@
//!
//! [`BinaryHeap`]: `crate::binary_heap::BinaryHeap`
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt;
use core::marker::PhantomData;
@ -34,7 +33,80 @@ use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
use core::ptr;
use crate::storage::{OwnedStorage, Storage, ViewStorage};
mod storage {
use super::Node;
/// Trait defining how data for a container is stored.
///
/// There's two implementations available:
///
/// - [`OwnedSortedLinkedListStorage`]: stores the data in an array `[T; N]` whose size is known at compile time.
/// - [`ViewSortedLinkedListStorage`]: stores the data in an unsized `[T]`.
///
/// This allows [`SortedLinkedList`] to be generic over either sized or unsized storage. The [`sorted_linked_list`](super)
/// module contains a [`SortedLinkedListInner`] struct that's generic on [`SortedLinkedListStorage`],
/// and two type aliases for convenience:
///
/// - [`SortedLinkedList<T, Idx, N>`](super::SortedLinkedList) = `SortedLinkedListInner<T, OwnedSortedLinkedListStorage<T, Idx, N>>`
/// - [`SortedLinkedListView<T, Idx>`](super::SortedLinkedListView) = `SortedLinkedListInner<T, ViewSortedLinkedListStorage<T, Idx>>`
///
/// `SortedLinkedList` can be unsized into `SortedLinkedListView`, either by unsizing coercions such as `&mut SortedLinkedList -> &mut SortedLinkedListView` or
/// `Box<SortedLinkedList> -> Box<SortedLinkedListView>`, or explicitly with [`.as_view()`](super::SortedLinkedList::as_view) or [`.as_mut_view()`](super::SortedLinkedList::as_mut_view).
///
/// This trait is sealed, so you cannot implement it for your own types. You can only use
/// the implementations provided by this crate.
///
/// [`SortedLinkedListInner`]: super::SortedLinkedListInner
/// [`SortedLinkedList`]: super::SortedLinkedList
/// [`SortedLinkedListView`]: super::SortedLinkedListView
#[allow(private_bounds)]
pub trait SortedLinkedListStorage<T, Idx>: SortedLinkedListSealedStorage<T, Idx> {}
pub trait SortedLinkedListSealedStorage<T, Idx> {
// part of the sealed trait so that no trait is publicly implemented by `OwnedSortedLinkedListStorage` besides `Storage`
fn borrow(&self) -> &[Node<T, Idx>];
fn borrow_mut(&mut self) -> &mut [Node<T, Idx>];
}
// One sealed layer of indirection to hide the internal details (The MaybeUninit).
pub struct SortedLinkedListStorageInner<T: ?Sized> {
pub(crate) buffer: T,
}
/// Implementation of [`SortedLinkedListStorage`] that stores the data in an array `[T; N]` whose size is known at compile time.
pub type OwnedSortedLinkedListStorage<T, Idx, const N: usize> =
SortedLinkedListStorageInner<[Node<T, Idx>; N]>;
/// Implementation of [`SortedLinkedListStorage`] that stores the data in an unsized `[T]`.
pub type ViewSortedLinkedListStorage<T, Idx> = SortedLinkedListStorageInner<[Node<T, Idx>]>;
impl<T, Idx, const N: usize> SortedLinkedListSealedStorage<T, Idx>
for OwnedSortedLinkedListStorage<T, Idx, N>
{
fn borrow(&self) -> &[Node<T, Idx>] {
&self.buffer
}
fn borrow_mut(&mut self) -> &mut [Node<T, Idx>] {
&mut self.buffer
}
}
impl<T, Idx, const N: usize> SortedLinkedListStorage<T, Idx>
for OwnedSortedLinkedListStorage<T, Idx, N>
{
}
impl<T, Idx> SortedLinkedListSealedStorage<T, Idx> for ViewSortedLinkedListStorage<T, Idx> {
fn borrow(&self) -> &[Node<T, Idx>] {
&self.buffer
}
fn borrow_mut(&mut self) -> &mut [Node<T, Idx>] {
&mut self.buffer
}
}
impl<T, Idx> SortedLinkedListStorage<T, Idx> for ViewSortedLinkedListStorage<T, Idx> {}
}
pub use storage::{
OwnedSortedLinkedListStorage, SortedLinkedListStorage, ViewSortedLinkedListStorage,
};
/// Trait for defining an index for the linked list, never implemented by users.
pub trait SortedLinkedListIndex: Copy {
@ -86,27 +158,28 @@ pub struct Node<T, Idx> {
next: Idx,
}
/// Base struct for [`SortedLinkedList`] and [`SortedLinkedListView`], generic over the [`Storage`].
/// Base struct for [`SortedLinkedList`] and [`SortedLinkedListView`], generic over the [`SortedLinkedListStorage`].
///
/// In most cases you should use [`SortedLinkedList`] or [`SortedLinkedListView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct SortedLinkedListInner<T, Idx, K, S>
where
Idx: SortedLinkedListIndex,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
head: Idx,
free: Idx,
_kind: PhantomData<K>,
list: S::Buffer<Node<T, Idx>>,
phantom: PhantomData<(K, T)>,
list: S,
}
/// The linked list.
pub type SortedLinkedList<T, Idx, K, const N: usize> =
SortedLinkedListInner<T, Idx, K, OwnedStorage<N>>;
SortedLinkedListInner<T, Idx, K, OwnedSortedLinkedListStorage<T, Idx, N>>;
/// The linked list.
pub type SortedLinkedListView<T, Idx, K> = SortedLinkedListInner<T, Idx, K, ViewStorage>;
pub type SortedLinkedListView<T, Idx, K> =
SortedLinkedListInner<T, Idx, K, ViewSortedLinkedListStorage<T, Idx>>;
// Internal macro for generating indexes for the linkedlist and const new for the linked list
macro_rules! impl_index_and_const_new {
@ -168,10 +241,12 @@ macro_rules! impl_index_and_const_new {
crate::sealed::smaller_than::<N, $max_val>();
let mut list = SortedLinkedList {
list: [Self::UNINIT; N],
list: OwnedSortedLinkedListStorage {
buffer: [Self::UNINIT; N],
},
head: $name::none(),
free: unsafe { $name::new_unchecked(0) },
_kind: PhantomData,
phantom: PhantomData,
};
if N == 0 {
@ -183,7 +258,7 @@ macro_rules! impl_index_and_const_new {
// Initialize indexes
while free < N - 1 {
list.list[free].next = unsafe { $name::new_unchecked(free as $ty + 1) };
list.list.buffer[free].next = unsafe { $name::new_unchecked(free as $ty + 1) };
free += 1;
}
@ -215,7 +290,7 @@ where
impl<T, Idx, K, S> SortedLinkedListInner<T, Idx, K, S>
where
Idx: SortedLinkedListIndex,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
/// Internal access helper
#[inline(always)]
@ -267,7 +342,7 @@ where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
/// Pushes a value onto the list without checking if the list is full.
///
@ -545,7 +620,7 @@ where
}
}
/// Base struct for [`Iter`] and [`IterView`], generic over the [`Storage`].
/// Base struct for [`Iter`] and [`IterView`], generic over the [`SortedLinkedListStorage`].
///
/// In most cases you should use [`Iter`] or [`IterView`] directly. Only use this
/// struct if you want to write code that's generic over both.
@ -554,23 +629,24 @@ where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
list: &'a SortedLinkedListInner<T, Idx, K, S>,
index: Idx,
}
/// Iterator for the linked list.
pub type Iter<'a, T, Idx, K, const N: usize> = IterInner<'a, T, Idx, K, OwnedStorage<N>>;
pub type Iter<'a, T, Idx, K, const N: usize> =
IterInner<'a, T, Idx, K, OwnedSortedLinkedListStorage<T, Idx, N>>;
/// Iterator for the linked list.
pub type IterView<'a, T, Idx, K, const N: usize> = IterInner<'a, T, Idx, K, ViewStorage>;
pub type IterView<'a, T, Idx, K> = IterInner<'a, T, Idx, K, ViewSortedLinkedListStorage<T, Idx>>;
impl<'a, T, Idx, K, S> Iterator for IterInner<'a, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
type Item = &'a T;
@ -584,7 +660,7 @@ where
}
}
/// Base struct for [`FindMut`] and [`FindMutView`], generic over the [`Storage`].
/// Base struct for [`FindMut`] and [`FindMutView`], generic over the [`SortedLinkedListStorage`].
///
/// In most cases you should use [`FindMut`] or [`FindMutView`] directly. Only use this
/// struct if you want to write code that's generic over both.
@ -593,7 +669,7 @@ where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
list: &'a mut SortedLinkedListInner<T, Idx, K, S>,
is_head: bool,
@ -603,16 +679,18 @@ where
}
/// Comes from [`SortedLinkedList::find_mut`].
pub type FindMut<'a, T, Idx, K, const N: usize> = FindMutInner<'a, T, Idx, K, OwnedStorage<N>>;
pub type FindMut<'a, T, Idx, K, const N: usize> =
FindMutInner<'a, T, Idx, K, OwnedSortedLinkedListStorage<T, Idx, N>>;
/// Comes from [`SortedLinkedList::find_mut`].
pub type FindMutView<'a, T, Idx, K, const N: usize> = FindMutInner<'a, T, Idx, K, ViewStorage>;
pub type FindMutView<'a, T, Idx, K, const N: usize> =
FindMutInner<'a, T, Idx, K, ViewSortedLinkedListStorage<T, Idx>>;
impl<T, Idx, K, S> FindMutInner<'_, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
fn pop_internal(&mut self) -> T {
if self.is_head {
@ -701,7 +779,7 @@ where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
fn drop(&mut self) {
// Only resort the list if the element has changed
@ -717,7 +795,7 @@ where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
type Target = T;
@ -732,7 +810,7 @@ where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.maybe_changed = true;
@ -771,7 +849,7 @@ where
T: Ord + core::fmt::Debug,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
@ -781,7 +859,7 @@ where
impl<T, Idx, K, S> Drop for SortedLinkedListInner<T, Idx, K, S>
where
Idx: SortedLinkedListIndex,
S: Storage,
S: SortedLinkedListStorage<T, Idx> + ?Sized,
{
fn drop(&mut self) {
let mut index = self.head;
@ -927,4 +1005,15 @@ mod tests {
assert_eq!(ll.peek().unwrap(), &1001);
}
fn _test_variance<'a: 'b, 'b>(
x: SortedLinkedList<&'a (), LinkedIndexUsize, Max, 42>,
) -> SortedLinkedList<&'b (), LinkedIndexUsize, Max, 42> {
x
}
fn _test_variance_view<'a: 'b, 'b, 'c>(
x: &'c SortedLinkedListView<&'a (), LinkedIndexUsize, Max>,
) -> &'c SortedLinkedListView<&'b (), LinkedIndexUsize, Max> {
x
}
}

View File

@ -11,11 +11,7 @@ use core::{
str::{self, Utf8Error},
};
use crate::{
storage::{OwnedStorage, Storage, ViewStorage},
vec::VecInner,
Vec,
};
use crate::vec::{OwnedVecStorage, Vec, VecInner, VecStorage, ViewVecStorage};
mod drain;
pub use drain::Drain;
@ -42,19 +38,19 @@ impl fmt::Display for FromUtf16Error {
}
}
/// Base struct for [`String`] and [`StringView`], generic over the [`Storage`].
/// Base struct for [`String`] and [`StringView`], generic over the [`VecStorage`].
///
/// In most cases you should use [`String`] or [`StringView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct StringInner<S: Storage> {
pub struct StringInner<S: VecStorage<u8> + ?Sized> {
vec: VecInner<u8, S>,
}
/// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
pub type String<const N: usize> = StringInner<OwnedStorage<N>>;
pub type String<const N: usize> = StringInner<OwnedVecStorage<u8, N>>;
/// A dynamic capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
pub type StringView = StringInner<ViewStorage>;
pub type StringView = StringInner<ViewVecStorage<u8>>;
impl StringView {
/// Removes the specified range from the string in bulk, returning all
@ -349,7 +345,7 @@ impl<const N: usize> String<N> {
}
}
impl<S: Storage> StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> StringInner<S> {
/// Extracts a string slice containing the entire string.
///
/// # Examples
@ -690,26 +686,26 @@ impl<const N: usize> Clone for String<N> {
}
}
impl<S: Storage> fmt::Debug for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> fmt::Debug for StringInner<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<str as fmt::Debug>::fmt(self, f)
}
}
impl<S: Storage> fmt::Display for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> fmt::Display for StringInner<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<str as fmt::Display>::fmt(self, f)
}
}
impl<S: Storage> hash::Hash for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> hash::Hash for StringInner<S> {
#[inline]
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
<str as hash::Hash>::hash(self, hasher)
}
}
impl<S: Storage> fmt::Write for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> fmt::Write for StringInner<S> {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
self.push_str(s).map_err(|_| fmt::Error)
}
@ -719,7 +715,7 @@ impl<S: Storage> fmt::Write for StringInner<S> {
}
}
impl<S: Storage> ops::Deref for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> ops::Deref for StringInner<S> {
type Target = str;
fn deref(&self) -> &str {
@ -727,45 +723,47 @@ impl<S: Storage> ops::Deref for StringInner<S> {
}
}
impl<S: Storage> ops::DerefMut for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> ops::DerefMut for StringInner<S> {
fn deref_mut(&mut self) -> &mut str {
self.as_mut_str()
}
}
impl<S: Storage> borrow::Borrow<str> for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> borrow::Borrow<str> for StringInner<S> {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl<S: Storage> borrow::BorrowMut<str> for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> borrow::BorrowMut<str> for StringInner<S> {
fn borrow_mut(&mut self) -> &mut str {
self.as_mut_str()
}
}
impl<S: Storage> AsRef<str> for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> AsRef<str> for StringInner<S> {
#[inline]
fn as_ref(&self) -> &str {
self
}
}
impl<S: Storage> AsRef<[u8]> for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> AsRef<[u8]> for StringInner<S> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<S1: Storage, S2: Storage> PartialEq<StringInner<S1>> for StringInner<S2> {
impl<S1: VecStorage<u8> + ?Sized, S2: VecStorage<u8> + ?Sized> PartialEq<StringInner<S1>>
for StringInner<S2>
{
fn eq(&self, rhs: &StringInner<S1>) -> bool {
str::eq(&**self, &**rhs)
}
}
// String<N> == str
impl<S: Storage> PartialEq<str> for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> PartialEq<str> for StringInner<S> {
#[inline]
fn eq(&self, other: &str) -> bool {
str::eq(self, other)
@ -773,7 +771,7 @@ impl<S: Storage> PartialEq<str> for StringInner<S> {
}
// String<N> == &'str
impl<S: Storage> PartialEq<&str> for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> PartialEq<&str> for StringInner<S> {
#[inline]
fn eq(&self, other: &&str) -> bool {
str::eq(self, &other[..])
@ -781,7 +779,7 @@ impl<S: Storage> PartialEq<&str> for StringInner<S> {
}
// str == String<N>
impl<S: Storage> PartialEq<StringInner<S>> for str {
impl<S: VecStorage<u8> + ?Sized> PartialEq<StringInner<S>> for str {
#[inline]
fn eq(&self, other: &StringInner<S>) -> bool {
str::eq(self, &other[..])
@ -789,23 +787,25 @@ impl<S: Storage> PartialEq<StringInner<S>> for str {
}
// &'str == String<N>
impl<S: Storage> PartialEq<StringInner<S>> for &str {
impl<S: VecStorage<u8> + ?Sized> PartialEq<StringInner<S>> for &str {
#[inline]
fn eq(&self, other: &StringInner<S>) -> bool {
str::eq(self, &other[..])
}
}
impl<S: Storage> Eq for StringInner<S> {}
impl<S: VecStorage<u8> + ?Sized> Eq for StringInner<S> {}
impl<S1: Storage, S2: Storage> PartialOrd<StringInner<S1>> for StringInner<S2> {
impl<S1: VecStorage<u8> + ?Sized, S2: VecStorage<u8> + ?Sized> PartialOrd<StringInner<S1>>
for StringInner<S2>
{
#[inline]
fn partial_cmp(&self, other: &StringInner<S1>) -> Option<Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
}
impl<S: Storage> Ord for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> Ord for StringInner<S> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(&**self, &**other)

View File

@ -1,14 +1,17 @@
use crate::{storage::Storage, string::StringInner, vec::VecInner};
use crate::{
string::StringInner,
vec::{VecInner, VecStorage},
};
use ufmt_write::uWrite;
impl<S: Storage> uWrite for StringInner<S> {
impl<S: VecStorage<u8> + ?Sized> uWrite for StringInner<S> {
type Error = ();
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.push_str(s)
}
}
impl<S: Storage> uWrite for VecInner<u8, S> {
impl<S: VecStorage<u8> + ?Sized> uWrite for VecInner<u8, S> {
type Error = ();
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.extend_from_slice(s.as_bytes())

View File

@ -1,8 +1,8 @@
//! A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html).
use core::borrow;
use core::marker::PhantomData;
use core::{
borrow::{Borrow, BorrowMut},
cmp::Ordering,
fmt, hash,
mem::{self, ManuallyDrop, MaybeUninit},
@ -11,18 +11,87 @@ use core::{
slice,
};
use crate::storage::{OwnedStorage, Storage, ViewStorage};
mod drain;
mod storage {
use core::mem::MaybeUninit;
/// Trait defining how data for a container is stored.
///
/// There's two implementations available:
///
/// - [`OwnedVecStorage`]: stores the data in an array `[T; N]` whose size is known at compile time.
/// - [`ViewVecStorage`]: stores the data in an unsized `[T]`.
///
/// This allows [`Vec`] to be generic over either sized or unsized storage. The [`vec`](super)
/// module contains a [`VecInner`] struct that's generic on [`VecStorage`],
/// and two type aliases for convenience:
///
/// - [`Vec<T, N>`](crate::vec::Vec) = `VecInner<T, OwnedStorage<T, N>>`
/// - [`VecView<T>`](crate::vec::VecView) = `VecInner<T, ViewStorage<T>>`
///
/// `Vec` can be unsized into `VecView`, either by unsizing coercions such as `&mut Vec -> &mut VecView` or
/// `Box<Vec> -> Box<VecView>`, or explicitly with [`.as_view()`](crate::vec::Vec::as_view) or [`.as_mut_view()`](crate::vec::Vec::as_mut_view).
///
/// This trait is sealed, so you cannot implement it for your own types. You can only use
/// the implementations provided by this crate.
///
/// [`VecInner`]: super::VecInner
/// [`Vec`]: super::Vec
/// [`VecView`]: super::VecView
#[allow(private_bounds)]
pub trait VecStorage<T>: VecSealedStorage<T> {}
pub trait VecSealedStorage<T> {
// part of the sealed trait so that no trait is publicly implemented by `OwnedVecStorage` besides `Storage`
fn borrow(&self) -> &[MaybeUninit<T>];
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>];
}
// One sealed layer of indirection to hide the internal details (The MaybeUninit).
pub struct VecStorageInner<T: ?Sized> {
pub(crate) buffer: T,
}
/// Implementation of [`VecStorage`] that stores the data in an array `[T; N]` whose size is known at compile time.
pub type OwnedVecStorage<T, const N: usize> = VecStorageInner<[MaybeUninit<T>; N]>;
/// Implementation of [`VecStorage`] that stores the data in an unsized `[T]`.
pub type ViewVecStorage<T> = VecStorageInner<[MaybeUninit<T>]>;
impl<T, const N: usize> VecSealedStorage<T> for OwnedVecStorage<T, N> {
fn borrow(&self) -> &[MaybeUninit<T>] {
&self.buffer
}
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>] {
&mut self.buffer
}
}
impl<T, const N: usize> VecStorage<T> for OwnedVecStorage<T, N> {}
impl<T> VecSealedStorage<T> for ViewVecStorage<T> {
fn borrow(&self) -> &[MaybeUninit<T>] {
&self.buffer
}
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>] {
&mut self.buffer
}
}
impl<T> VecStorage<T> for ViewVecStorage<T> {}
}
pub use storage::{OwnedVecStorage, VecStorage, ViewVecStorage};
pub(crate) use storage::VecStorageInner;
pub use drain::Drain;
/// Base struct for [`Vec`] and [`VecView`], generic over the [`Storage`].
/// Base struct for [`Vec`] and [`VecView`], generic over the [`VecStorage`].
///
/// In most cases you should use [`Vec`] or [`VecView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct VecInner<T, S: Storage> {
pub struct VecInner<T, S: VecStorage<T> + ?Sized> {
phantom: PhantomData<T>,
len: usize,
buffer: S::Buffer<MaybeUninit<T>>,
buffer: S,
}
/// A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html).
@ -62,7 +131,7 @@ pub struct VecInner<T, S: Storage> {
/// let vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
/// let view: &VecView<_> = &vec;
/// ```
pub type Vec<T, const N: usize> = VecInner<T, OwnedStorage<N>>;
pub type Vec<T, const N: usize> = VecInner<T, OwnedVecStorage<T, N>>;
/// A [`Vec`] with dynamic capacity
///
@ -85,7 +154,7 @@ pub type Vec<T, const N: usize> = VecInner<T, OwnedStorage<N>>;
/// mut_view.push(5);
/// assert_eq!(vec, [1, 2, 3, 4, 5]);
/// ```
pub type VecView<T> = VecInner<T, ViewStorage>;
pub type VecView<T> = VecInner<T, ViewVecStorage<T>>;
impl<T, const N: usize> Vec<T, N> {
const ELEM: MaybeUninit<T> = MaybeUninit::uninit();
@ -106,8 +175,9 @@ impl<T, const N: usize> Vec<T, N> {
/// ```
pub const fn new() -> Self {
Self {
phantom: PhantomData,
len: 0,
buffer: Self::INIT,
buffer: VecStorageInner { buffer: Self::INIT },
}
}
@ -152,6 +222,7 @@ impl<T, const N: usize> Vec<T, N> {
if N == M {
Self {
phantom: PhantomData,
len: N,
// NOTE(unsafe) ManuallyDrop<[T; M]> and [MaybeUninit<T>; N]
// have the same layout when N == M.
@ -160,7 +231,7 @@ impl<T, const N: usize> Vec<T, N> {
} else {
let mut v = Vec::<T, N>::new();
for (src_elem, dst_elem) in src.iter().zip(v.buffer.iter_mut()) {
for (src_elem, dst_elem) in src.iter().zip(v.buffer.buffer.iter_mut()) {
// NOTE(unsafe) src element is not going to drop as src itself
// is wrapped in a ManuallyDrop.
dst_elem.write(unsafe { ptr::read(src_elem) });
@ -296,7 +367,7 @@ impl<T, const N: usize> Vec<T, N> {
///
/// This method is not available on a `VecView`, use [`storage_len`](VecInner::storage_capacity) instead
pub const fn capacity(&self) -> usize {
self.buffer.len()
self.buffer.buffer.len()
}
}
@ -365,7 +436,7 @@ impl<T> VecView<T> {
}
}
impl<T, S: Storage> VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
/// Returns a raw pointer to the vectors buffer.
pub fn as_ptr(&self) -> *const T {
self.buffer.borrow().as_ptr() as *const T
@ -993,14 +1064,14 @@ impl<T, S: Storage> VecInner<T, S> {
// This drop guard will be invoked when predicate or `drop` of element panicked.
// It shifts unchecked elements to cover holes and `set_len` to the correct length.
// In cases when predicate and `drop` never panick, it will be optimized out.
struct BackshiftOnDrop<'a, T, S: Storage> {
struct BackshiftOnDrop<'a, T, S: VecStorage<T> + ?Sized> {
v: &'a mut VecInner<T, S>,
processed_len: usize,
deleted_cnt: usize,
original_len: usize,
}
impl<T, S: Storage> Drop for BackshiftOnDrop<'_, T, S> {
impl<T, S: VecStorage<T> + ?Sized> Drop for BackshiftOnDrop<'_, T, S> {
fn drop(&mut self) {
if self.deleted_cnt > 0 {
// SAFETY: Trailing unchecked items must be valid since we never touch them.
@ -1028,7 +1099,7 @@ impl<T, S: Storage> VecInner<T, S> {
original_len,
};
fn process_loop<F, T, S: Storage, const DELETED: bool>(
fn process_loop<F, T, S: VecStorage<T> + ?Sized, const DELETED: bool>(
original_len: usize,
f: &mut F,
g: &mut BackshiftOnDrop<'_, T, S>,
@ -1114,7 +1185,7 @@ impl<T, const N: usize> Default for Vec<T, N> {
}
}
impl<T, S: Storage> fmt::Debug for VecInner<T, S>
impl<T, S: VecStorage<T> + ?Sized> fmt::Debug for VecInner<T, S>
where
T: fmt::Debug,
{
@ -1123,7 +1194,7 @@ where
}
}
impl<S: Storage> fmt::Write for VecInner<u8, S> {
impl<S: VecStorage<u8> + ?Sized> fmt::Write for VecInner<u8, S> {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.extend_from_slice(s.as_bytes()) {
Ok(()) => Ok(()),
@ -1138,7 +1209,7 @@ impl<T, const N: usize, const M: usize> From<[T; M]> for Vec<T, N> {
}
}
impl<T, S: Storage> Drop for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> Drop for VecInner<T, S> {
fn drop(&mut self) {
let mut_slice = self.as_mut_slice();
// We drop each element used in the vector by turning into a `&mut [T]`.
@ -1155,7 +1226,7 @@ impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec<T, N> {
}
}
impl<T, S: Storage> Extend<T> for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> Extend<T> for VecInner<T, S> {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
@ -1164,7 +1235,7 @@ impl<T, S: Storage> Extend<T> for VecInner<T, S> {
}
}
impl<'a, T, S: Storage> Extend<&'a T> for VecInner<T, S>
impl<'a, T, S: VecStorage<T> + ?Sized> Extend<&'a T> for VecInner<T, S>
where
T: 'a + Copy,
{
@ -1176,7 +1247,7 @@ where
}
}
impl<T, S: Storage> hash::Hash for VecInner<T, S>
impl<T, S: VecStorage<T> + ?Sized> hash::Hash for VecInner<T, S>
where
T: core::hash::Hash,
{
@ -1185,7 +1256,7 @@ where
}
}
impl<'a, T, S: Storage> IntoIterator for &'a VecInner<T, S> {
impl<'a, T, S: VecStorage<T> + ?Sized> IntoIterator for &'a VecInner<T, S> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
@ -1194,7 +1265,7 @@ impl<'a, T, S: Storage> IntoIterator for &'a VecInner<T, S> {
}
}
impl<'a, T, S: Storage> IntoIterator for &'a mut VecInner<T, S> {
impl<'a, T, S: VecStorage<T> + ?Sized> IntoIterator for &'a mut VecInner<T, S> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
@ -1228,7 +1299,14 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.next < self.vec.len() {
let item = unsafe { self.vec.buffer.get_unchecked_mut(self.next).as_ptr().read() };
let item = unsafe {
self.vec
.buffer
.buffer
.get_unchecked_mut(self.next)
.as_ptr()
.read()
};
self.next += 1;
Some(item)
} else {
@ -1247,7 +1325,7 @@ where
if self.next < self.vec.len() {
let s = unsafe {
slice::from_raw_parts(
(self.vec.buffer.as_ptr() as *const T).add(self.next),
(self.vec.buffer.buffer.as_ptr() as *const T).add(self.next),
self.vec.len() - self.next,
)
};
@ -1278,7 +1356,8 @@ impl<T, const N: usize> IntoIterator for Vec<T, N> {
}
}
impl<A, B, SA: Storage, SB: Storage> PartialEq<VecInner<B, SB>> for VecInner<A, SA>
impl<A, B, SA: VecStorage<A> + ?Sized, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>>
for VecInner<A, SA>
where
A: PartialEq<B>,
{
@ -1287,7 +1366,7 @@ where
}
}
impl<A, B, const M: usize, SB: Storage> PartialEq<VecInner<B, SB>> for [A; M]
impl<A, B, const M: usize, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>> for [A; M]
where
A: PartialEq<B>,
{
@ -1296,7 +1375,7 @@ where
}
}
impl<A, B, SB: Storage, const M: usize> PartialEq<VecInner<B, SB>> for &[A; M]
impl<A, B, SB: VecStorage<B> + ?Sized, const M: usize> PartialEq<VecInner<B, SB>> for &[A; M]
where
A: PartialEq<B>,
{
@ -1305,7 +1384,7 @@ where
}
}
impl<A, B, SB: Storage> PartialEq<VecInner<B, SB>> for [A]
impl<A, B, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>> for [A]
where
A: PartialEq<B>,
{
@ -1314,7 +1393,7 @@ where
}
}
impl<A, B, SB: Storage> PartialEq<VecInner<B, SB>> for &[A]
impl<A, B, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>> for &[A]
where
A: PartialEq<B>,
{
@ -1323,7 +1402,7 @@ where
}
}
impl<A, B, SB: Storage> PartialEq<VecInner<B, SB>> for &mut [A]
impl<A, B, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>> for &mut [A]
where
A: PartialEq<B>,
{
@ -1332,7 +1411,7 @@ where
}
}
impl<A, B, SA: Storage, const N: usize> PartialEq<[B; N]> for VecInner<A, SA>
impl<A, B, SA: VecStorage<A> + ?Sized, const N: usize> PartialEq<[B; N]> for VecInner<A, SA>
where
A: PartialEq<B>,
{
@ -1342,7 +1421,7 @@ where
}
}
impl<A, B, SA: Storage, const N: usize> PartialEq<&[B; N]> for VecInner<A, SA>
impl<A, B, SA: VecStorage<A> + ?Sized, const N: usize> PartialEq<&[B; N]> for VecInner<A, SA>
where
A: PartialEq<B>,
{
@ -1352,7 +1431,7 @@ where
}
}
impl<A, B, SA: Storage> PartialEq<[B]> for VecInner<A, SA>
impl<A, B, SA: VecStorage<A> + ?Sized> PartialEq<[B]> for VecInner<A, SA>
where
A: PartialEq<B>,
{
@ -1362,7 +1441,7 @@ where
}
}
impl<A, B, SA: Storage> PartialEq<&[B]> for VecInner<A, SA>
impl<A, B, SA: VecStorage<A> + ?Sized> PartialEq<&[B]> for VecInner<A, SA>
where
A: PartialEq<B>,
{
@ -1372,7 +1451,7 @@ where
}
}
impl<A, B, SA: Storage> PartialEq<&mut [B]> for VecInner<A, SA>
impl<A, B, SA: VecStorage<A> + ?Sized> PartialEq<&mut [B]> for VecInner<A, SA>
where
A: PartialEq<B>,
{
@ -1383,9 +1462,10 @@ where
}
// Implements Eq if underlying data is Eq
impl<T, S: Storage> Eq for VecInner<T, S> where T: Eq {}
impl<T, S: VecStorage<T> + ?Sized> Eq for VecInner<T, S> where T: Eq {}
impl<T, SA: Storage, SB: Storage> PartialOrd<VecInner<T, SA>> for VecInner<T, SB>
impl<T, SA: VecStorage<T> + ?Sized, SB: VecStorage<T> + ?Sized> PartialOrd<VecInner<T, SA>>
for VecInner<T, SB>
where
T: PartialOrd,
{
@ -1394,7 +1474,7 @@ where
}
}
impl<T, S: Storage> Ord for VecInner<T, S>
impl<T, S: VecStorage<T> + ?Sized> Ord for VecInner<T, S>
where
T: Ord,
{
@ -1404,7 +1484,7 @@ where
}
}
impl<T, S: Storage> ops::Deref for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> ops::Deref for VecInner<T, S> {
type Target = [T];
fn deref(&self) -> &Self::Target {
@ -1412,45 +1492,45 @@ impl<T, S: Storage> ops::Deref for VecInner<T, S> {
}
}
impl<T, S: Storage> ops::DerefMut for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> ops::DerefMut for VecInner<T, S> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<T, S: Storage> borrow::Borrow<[T]> for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> borrow::Borrow<[T]> for VecInner<T, S> {
fn borrow(&self) -> &[T] {
self.as_slice()
}
}
impl<T, S: Storage> borrow::BorrowMut<[T]> for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> borrow::BorrowMut<[T]> for VecInner<T, S> {
fn borrow_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T, S: Storage> AsRef<VecInner<T, S>> for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> AsRef<VecInner<T, S>> for VecInner<T, S> {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl<T, S: Storage> AsMut<VecInner<T, S>> for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> AsMut<VecInner<T, S>> for VecInner<T, S> {
#[inline]
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<T, S: Storage> AsRef<[T]> for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> AsRef<[T]> for VecInner<T, S> {
#[inline]
fn as_ref(&self) -> &[T] {
self
}
}
impl<T, S: Storage> AsMut<[T]> for VecInner<T, S> {
impl<T, S: VecStorage<T> + ?Sized> AsMut<[T]> for VecInner<T, S> {
#[inline]
fn as_mut(&mut self) -> &mut [T] {
self
@ -1959,4 +2039,11 @@ mod tests {
assert!(v.spare_capacity_mut().is_empty());
}
fn _test_variance<'a: 'b, 'b>(x: Vec<&'a (), 42>) -> Vec<&'b (), 42> {
x
}
fn _test_variance_view<'a: 'b, 'b, 'c>(x: &'c VecView<&'a ()>) -> &'c VecView<&'b ()> {
x
}
}