mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-09-30 05:50:29 +00:00
Merge pull request #500 from Nitrokey/vec-drain-generic
Implement `Vec::drain`, `as_(mut_)view` on the `*Inner` types, generic over `Storage`
This commit is contained in:
commit
4b78bc1bb9
@ -184,14 +184,16 @@ impl<T, K, const N: usize> BinaryHeap<T, K, N> {
|
||||
pub fn into_vec(self) -> Vec<T, N> {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, K, S: VecStorage<T>> BinaryHeapInner<T, K, S> {
|
||||
/// Get a reference to the `BinaryHeap`, erasing the `N` const-generic.
|
||||
pub fn as_view(&self) -> &BinaryHeapView<T, K> {
|
||||
self
|
||||
S::as_binary_heap_view(self)
|
||||
}
|
||||
/// Get a mutable reference to the `BinaryHeap`, erasing the `N` const-generic.
|
||||
pub fn as_mut_view(&mut self) -> &mut BinaryHeapView<T, K> {
|
||||
self
|
||||
S::as_binary_heap_mut_view(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Defmt implementations for heapless types
|
||||
|
||||
use crate::{
|
||||
string::StringInner,
|
||||
string::{StringInner, StringStorage},
|
||||
vec::{VecInner, VecStorage},
|
||||
};
|
||||
use defmt::Formatter;
|
||||
@ -15,7 +15,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> defmt::Format for StringInner<S>
|
||||
impl<S: StringStorage + ?Sized> defmt::Format for StringInner<S>
|
||||
where
|
||||
u8: defmt::Format,
|
||||
{
|
||||
|
@ -186,19 +186,19 @@ impl<T, const N: usize> Deque<T, N> {
|
||||
self.back - self.front
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
|
||||
/// Get a reference to the `Deque`, erasing the `N` const-generic.
|
||||
pub fn as_view(&self) -> &DequeView<T> {
|
||||
self
|
||||
S::as_deque_view(self)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `Deque`, erasing the `N` const-generic.
|
||||
pub fn as_mut_view(&mut self) -> &mut DequeView<T> {
|
||||
self
|
||||
S::as_deque_mut_view(self)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -41,6 +41,8 @@ use core::slice;
|
||||
mod storage {
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use super::{HistoryBufferInner, HistoryBufferView};
|
||||
|
||||
/// Trait defining how data for a container is stored.
|
||||
///
|
||||
/// There's two implementations available:
|
||||
@ -72,6 +74,14 @@ mod storage {
|
||||
// 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>];
|
||||
fn as_hist_buf_view(this: &HistoryBufferInner<T, Self>) -> &HistoryBufferView<T>
|
||||
where
|
||||
Self: HistBufStorage<T>;
|
||||
fn as_hist_buf_mut_view(
|
||||
this: &mut HistoryBufferInner<T, Self>,
|
||||
) -> &mut HistoryBufferView<T>
|
||||
where
|
||||
Self: HistBufStorage<T>;
|
||||
}
|
||||
|
||||
// One sealed layer of indirection to hide the internal details (The MaybeUninit).
|
||||
@ -91,6 +101,18 @@ mod storage {
|
||||
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>] {
|
||||
&mut self.buffer
|
||||
}
|
||||
fn as_hist_buf_view(this: &HistoryBufferInner<T, Self>) -> &HistoryBufferView<T>
|
||||
where
|
||||
Self: HistBufStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_hist_buf_mut_view(this: &mut HistoryBufferInner<T, Self>) -> &mut HistoryBufferView<T>
|
||||
where
|
||||
Self: HistBufStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
impl<T, const N: usize> HistBufStorage<T> for OwnedHistBufStorage<T, N> {}
|
||||
|
||||
@ -101,6 +123,18 @@ mod storage {
|
||||
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>] {
|
||||
&mut self.buffer
|
||||
}
|
||||
fn as_hist_buf_view(this: &HistoryBufferInner<T, Self>) -> &HistoryBufferView<T>
|
||||
where
|
||||
Self: HistBufStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_hist_buf_mut_view(this: &mut HistoryBufferInner<T, Self>) -> &mut HistoryBufferView<T>
|
||||
where
|
||||
Self: HistBufStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
impl<T> HistBufStorage<T> for ViewHistBufStorage<T> {}
|
||||
}
|
||||
@ -221,18 +255,6 @@ impl<T, const N: usize> HistoryBuffer<T, N> {
|
||||
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>
|
||||
@ -264,6 +286,17 @@ where
|
||||
}
|
||||
}
|
||||
impl<T: Copy, S: HistBufStorage<T> + ?Sized> HistoryBufferInner<T, S> {
|
||||
/// Get a reference to the `HistoryBuffer`, erasing the `N` const-generic.
|
||||
#[inline]
|
||||
pub fn as_view(&self) -> &HistoryBufferView<T> {
|
||||
S::as_hist_buf_view(self)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `HistoryBuffer`, erasing the `N` const-generic.
|
||||
#[inline]
|
||||
pub fn as_mut_view(&mut self) -> &mut HistoryBufferView<T> {
|
||||
S::as_hist_buf_mut_view(self)
|
||||
}
|
||||
/// 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
|
||||
|
@ -181,6 +181,11 @@ pub mod storage;
|
||||
pub mod string;
|
||||
pub mod vec;
|
||||
|
||||
// Workaround a compiler ICE in rust 1.83 to 1.86
|
||||
// https://github.com/rust-lang/rust/issues/138979#issuecomment-2760839948
|
||||
#[expect(dead_code)]
|
||||
fn dead_code_ice_workaround() {}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod de;
|
||||
#[cfg(feature = "serde")]
|
||||
|
@ -4,22 +4,103 @@
|
||||
|
||||
use core::{borrow::Borrow, fmt, mem, ops, slice};
|
||||
|
||||
use crate::vec::{OwnedVecStorage, Vec, VecInner, VecStorage, ViewVecStorage};
|
||||
use crate::vec::{OwnedVecStorage, Vec, VecInner, ViewVecStorage};
|
||||
|
||||
mod storage {
|
||||
use crate::vec::{OwnedVecStorage, VecStorage, ViewVecStorage};
|
||||
|
||||
use super::{LinearMapInner, LinearMapView};
|
||||
|
||||
/// Trait defining how data for a [`LinearMap`](super::LinearMap) is stored.
|
||||
///
|
||||
/// There's two implementations available:
|
||||
///
|
||||
/// - [`OwnedStorage`]: stores the data in an array whose size is known at compile time.
|
||||
/// - [`ViewStorage`]: stores the data in an unsized slice
|
||||
///
|
||||
/// This allows [`LinearMap`] to be generic over either sized or unsized storage. The [`linear_map`](super)
|
||||
/// module contains a [`LinearMapInner`] struct that's generic on [`LinearMapStorage`],
|
||||
/// and two type aliases for convenience:
|
||||
///
|
||||
/// - [`LinearMap<N>`](crate::linear_map::LinearMap) = `LinearMapInner<OwnedStorage<u8, N>>`
|
||||
/// - [`LinearMapView<T>`](crate::linear_map::LinearMapView) = `LinearMapInner<ViewStorage<u8>>`
|
||||
///
|
||||
/// `LinearMap` can be unsized into `StrinsgView`, either by unsizing coercions such as `&mut LinearMap -> &mut LinearMapView` or
|
||||
/// `Box<LinearMap> -> Box<LinearMapView>`, or explicitly with [`.as_view()`](crate::linear_map::LinearMap::as_view) or [`.as_mut_view()`](crate::linear_map::LinearMap::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.
|
||||
///
|
||||
/// [`LinearMapInner`]: super::LinearMapInner
|
||||
/// [`LinearMap`]: super::LinearMap
|
||||
/// [`OwnedStorage`]: super::OwnedStorage
|
||||
/// [`ViewStorage`]: super::ViewStorage
|
||||
pub trait LinearMapStorage<K, V>: LinearMapStorageSealed<K, V> {}
|
||||
pub trait LinearMapStorageSealed<K, V>: VecStorage<(K, V)> {
|
||||
fn as_linear_map_view(this: &LinearMapInner<K, V, Self>) -> &LinearMapView<K, V>
|
||||
where
|
||||
Self: LinearMapStorage<K, V>;
|
||||
fn as_linear_map_mut_view(
|
||||
this: &mut LinearMapInner<K, V, Self>,
|
||||
) -> &mut LinearMapView<K, V>
|
||||
where
|
||||
Self: LinearMapStorage<K, V>;
|
||||
}
|
||||
|
||||
impl<K, V, const N: usize> LinearMapStorage<K, V> for OwnedVecStorage<(K, V), N> {}
|
||||
impl<K, V, const N: usize> LinearMapStorageSealed<K, V> for OwnedVecStorage<(K, V), N> {
|
||||
fn as_linear_map_view(this: &LinearMapInner<K, V, Self>) -> &LinearMapView<K, V>
|
||||
where
|
||||
Self: LinearMapStorage<K, V>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_linear_map_mut_view(this: &mut LinearMapInner<K, V, Self>) -> &mut LinearMapView<K, V>
|
||||
where
|
||||
Self: LinearMapStorage<K, V>,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> LinearMapStorage<K, V> for ViewVecStorage<(K, V)> {}
|
||||
|
||||
impl<K, V> LinearMapStorageSealed<K, V> for ViewVecStorage<(K, V)> {
|
||||
fn as_linear_map_view(this: &LinearMapInner<K, V, Self>) -> &LinearMapView<K, V>
|
||||
where
|
||||
Self: LinearMapStorage<K, V>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_linear_map_mut_view(this: &mut LinearMapInner<K, V, Self>) -> &mut LinearMapView<K, V>
|
||||
where
|
||||
Self: LinearMapStorage<K, V>,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use storage::LinearMapStorage;
|
||||
/// Implementation of [`LinearMapStorage`] that stores the data in an array whose size is known at compile time.
|
||||
pub type OwnedStorage<K, V, const N: usize> = OwnedVecStorage<(K, V), N>;
|
||||
/// Implementation of [`LinearMapStorage`] that stores the data in an unsized slice.
|
||||
pub type ViewStorage<K, V> = ViewVecStorage<(K, V)>;
|
||||
|
||||
/// Base struct for [`LinearMap`] and [`LinearMapView`]
|
||||
pub struct LinearMapInner<K, V, S: VecStorage<(K, V)> + ?Sized> {
|
||||
pub struct LinearMapInner<K, V, S: LinearMapStorage<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, OwnedVecStorage<(K, V), N>>;
|
||||
pub type LinearMap<K, V, const N: usize> = LinearMapInner<K, V, OwnedStorage<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, ViewVecStorage<(K, V)>>;
|
||||
pub type LinearMapView<K, V> = LinearMapInner<K, V, ViewStorage<K, V>>;
|
||||
|
||||
impl<K, V, const N: usize> LinearMap<K, V, N> {
|
||||
/// Creates an empty `LinearMap`.
|
||||
@ -38,22 +119,22 @@ impl<K, V, const N: usize> LinearMap<K, V, N> {
|
||||
pub const fn new() -> Self {
|
||||
Self { buffer: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S: LinearMapStorage<K, V> + ?Sized> LinearMapInner<K, V, S>
|
||||
where
|
||||
K: Eq,
|
||||
{
|
||||
/// Get a reference to the `LinearMap`, erasing the `N` const-generic.
|
||||
pub fn as_view(&self) -> &LinearMapView<K, V> {
|
||||
self
|
||||
S::as_linear_map_view(self)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `LinearMap`, erasing the `N` const-generic.
|
||||
pub fn as_mut_view(&mut self) -> &mut LinearMapView<K, V> {
|
||||
self
|
||||
S::as_linear_map_mut_view(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S: VecStorage<(K, V)> + ?Sized> LinearMapInner<K, V, S>
|
||||
where
|
||||
K: Eq,
|
||||
{
|
||||
/// Returns the number of elements that the map can hold.
|
||||
///
|
||||
/// Computes in *O*(1) time.
|
||||
@ -388,7 +469,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, Q, S: VecStorage<(K, V)> + ?Sized> ops::Index<&'_ Q> for LinearMapInner<K, V, S>
|
||||
impl<K, V, Q, S: LinearMapStorage<K, V> + ?Sized> ops::Index<&'_ Q> for LinearMapInner<K, V, S>
|
||||
where
|
||||
K: Borrow<Q> + Eq,
|
||||
Q: Eq + ?Sized,
|
||||
@ -400,7 +481,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, Q, S: VecStorage<(K, V)> + ?Sized> ops::IndexMut<&'_ Q> for LinearMapInner<K, V, S>
|
||||
impl<K, V, Q, S: LinearMapStorage<K, V> + ?Sized> ops::IndexMut<&'_ Q> for LinearMapInner<K, V, S>
|
||||
where
|
||||
K: Borrow<Q> + Eq,
|
||||
Q: Eq + ?Sized,
|
||||
@ -431,7 +512,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S: VecStorage<(K, V)> + ?Sized> fmt::Debug for LinearMapInner<K, V, S>
|
||||
impl<K, V, S: LinearMapStorage<K, V> + ?Sized> fmt::Debug for LinearMapInner<K, V, S>
|
||||
where
|
||||
K: Eq + fmt::Debug,
|
||||
V: fmt::Debug,
|
||||
@ -489,7 +570,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, S: VecStorage<(K, V)> + ?Sized> IntoIterator for &'a LinearMapInner<K, V, S>
|
||||
impl<'a, K, V, S: LinearMapStorage<K, V> + ?Sized> IntoIterator for &'a LinearMapInner<K, V, S>
|
||||
where
|
||||
K: Eq,
|
||||
{
|
||||
@ -533,7 +614,7 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S1: VecStorage<(K, V)> + ?Sized, S2: VecStorage<(K, V)> + ?Sized>
|
||||
impl<K, V, S1: LinearMapStorage<K, V> + ?Sized, S2: LinearMapStorage<K, V> + ?Sized>
|
||||
PartialEq<LinearMapInner<K, V, S2>> for LinearMapInner<K, V, S1>
|
||||
where
|
||||
K: Eq,
|
||||
@ -547,7 +628,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S: VecStorage<(K, V)> + ?Sized> Eq for LinearMapInner<K, V, S>
|
||||
impl<K, V, S: LinearMapStorage<K, V> + ?Sized> Eq for LinearMapInner<K, V, S>
|
||||
where
|
||||
K: Eq,
|
||||
V: PartialEq,
|
||||
|
20
src/mpmc.rs
20
src/mpmc.rs
@ -173,6 +173,18 @@ impl<T, const N: usize> MpMcQueue<T, N> {
|
||||
enqueue_pos: AtomicTargetSize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Used in `Storage` implementation
|
||||
pub(crate) fn as_view_private(&self) -> &MpMcQueueView<T> {
|
||||
self
|
||||
}
|
||||
/// Used in `Storage` implementation
|
||||
pub(crate) fn as_view_mut_private(&mut self) -> &mut MpMcQueueView<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S: Storage> MpMcQueueInner<T, S> {
|
||||
/// Get a reference to the `MpMcQueue`, erasing the `N` const-generic.
|
||||
///
|
||||
///
|
||||
@ -190,8 +202,8 @@ impl<T, const N: usize> MpMcQueue<T, N> {
|
||||
/// let view: &MpMcQueueView<u8> = &queue;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn as_view(&self) -> &MpMcQueueView<T> {
|
||||
self
|
||||
pub fn as_view(&self) -> &MpMcQueueView<T> {
|
||||
S::as_mpmc_view(self)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `MpMcQueue`, erasing the `N` const-generic.
|
||||
@ -211,11 +223,9 @@ impl<T, const N: usize> MpMcQueue<T, N> {
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut_view(&mut self) -> &mut MpMcQueueView<T> {
|
||||
self
|
||||
S::as_mpmc_mut_view(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S: Storage> MpMcQueueInner<T, S> {
|
||||
fn mask(&self) -> UintSize {
|
||||
(S::len(self.buffer.get()) - 1) as _
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ use crate::{
|
||||
binary_heap::{BinaryHeapInner, Kind as BinaryHeapKind},
|
||||
deque::DequeInner,
|
||||
histbuf::{HistBufStorage, HistoryBufferInner},
|
||||
linear_map::LinearMapInner,
|
||||
string::StringInner,
|
||||
linear_map::{LinearMapInner, LinearMapStorage},
|
||||
string::{StringInner, StringStorage},
|
||||
vec::{VecInner, VecStorage},
|
||||
IndexMap, IndexSet,
|
||||
};
|
||||
@ -116,7 +116,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S: VecStorage<(K, V)> + ?Sized> Serialize for LinearMapInner<K, V, S>
|
||||
impl<K, V, S: LinearMapStorage<K, V> + ?Sized> Serialize for LinearMapInner<K, V, S>
|
||||
where
|
||||
K: Eq + Serialize,
|
||||
V: Serialize,
|
||||
@ -135,7 +135,7 @@ where
|
||||
|
||||
// String containers
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> Serialize for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> Serialize for StringInner<S> {
|
||||
fn serialize<SER>(&self, serializer: SER) -> Result<SER::Ok, SER::Error>
|
||||
where
|
||||
SER: Serializer,
|
||||
|
@ -34,7 +34,7 @@ use core::ops::{Deref, DerefMut};
|
||||
use core::ptr;
|
||||
|
||||
mod storage {
|
||||
use super::Node;
|
||||
use super::{Node, SortedLinkedListIndex, SortedLinkedListInner, SortedLinkedListView};
|
||||
|
||||
/// Trait defining how data for a container is stored.
|
||||
///
|
||||
@ -66,6 +66,18 @@ mod storage {
|
||||
// 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>];
|
||||
fn as_view<K>(
|
||||
this: &SortedLinkedListInner<T, Idx, K, Self>,
|
||||
) -> &SortedLinkedListView<T, Idx, K>
|
||||
where
|
||||
Idx: SortedLinkedListIndex,
|
||||
Self: SortedLinkedListStorage<T, Idx>;
|
||||
fn as_mut_view<K>(
|
||||
this: &mut SortedLinkedListInner<T, Idx, K, Self>,
|
||||
) -> &mut SortedLinkedListView<T, Idx, K>
|
||||
where
|
||||
Idx: SortedLinkedListIndex,
|
||||
Self: SortedLinkedListStorage<T, Idx>;
|
||||
}
|
||||
|
||||
// One sealed layer of indirection to hide the internal details (The MaybeUninit).
|
||||
@ -88,6 +100,24 @@ mod storage {
|
||||
fn borrow_mut(&mut self) -> &mut [Node<T, Idx>] {
|
||||
&mut self.buffer
|
||||
}
|
||||
fn as_view<K>(
|
||||
this: &SortedLinkedListInner<T, Idx, K, Self>,
|
||||
) -> &SortedLinkedListView<T, Idx, K>
|
||||
where
|
||||
Self: SortedLinkedListStorage<T, Idx>,
|
||||
Idx: SortedLinkedListIndex,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_mut_view<K>(
|
||||
this: &mut SortedLinkedListInner<T, Idx, K, Self>,
|
||||
) -> &mut SortedLinkedListView<T, Idx, K>
|
||||
where
|
||||
Self: SortedLinkedListStorage<T, Idx>,
|
||||
Idx: SortedLinkedListIndex,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
impl<T, Idx, const N: usize> SortedLinkedListStorage<T, Idx>
|
||||
for OwnedSortedLinkedListStorage<T, Idx, N>
|
||||
@ -101,6 +131,24 @@ mod storage {
|
||||
fn borrow_mut(&mut self) -> &mut [Node<T, Idx>] {
|
||||
&mut self.buffer
|
||||
}
|
||||
fn as_view<K>(
|
||||
this: &SortedLinkedListInner<T, Idx, K, Self>,
|
||||
) -> &SortedLinkedListView<T, Idx, K>
|
||||
where
|
||||
Self: SortedLinkedListStorage<T, Idx>,
|
||||
Idx: SortedLinkedListIndex,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_mut_view<K>(
|
||||
this: &mut SortedLinkedListInner<T, Idx, K, Self>,
|
||||
) -> &mut SortedLinkedListView<T, Idx, K>
|
||||
where
|
||||
Self: SortedLinkedListStorage<T, Idx>,
|
||||
Idx: SortedLinkedListIndex,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
impl<T, Idx> SortedLinkedListStorage<T, Idx> for ViewSortedLinkedListStorage<T, Idx> {}
|
||||
}
|
||||
@ -273,26 +321,21 @@ impl_index_and_const_new!(LinkedIndexU8, u8, new_u8, { u8::MAX as usize - 1 });
|
||||
impl_index_and_const_new!(LinkedIndexU16, u16, new_u16, { u16::MAX as usize - 1 });
|
||||
impl_index_and_const_new!(LinkedIndexUsize, usize, new_usize, { usize::MAX - 1 });
|
||||
|
||||
impl<T, Idx, K, const N: usize> SortedLinkedList<T, Idx, K, N>
|
||||
where
|
||||
Idx: SortedLinkedListIndex,
|
||||
{
|
||||
/// Get a reference to the `SortedLinkedList`, erasing the `N` const-generic.
|
||||
pub fn as_view(&self) -> &SortedLinkedListView<T, Idx, K> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `Vec`, erasing the `N` const-generic.
|
||||
pub fn as_mut_view(&mut self) -> &mut SortedLinkedListView<T, Idx, K> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Idx, K, S> SortedLinkedListInner<T, Idx, K, S>
|
||||
where
|
||||
Idx: SortedLinkedListIndex,
|
||||
S: SortedLinkedListStorage<T, Idx> + ?Sized,
|
||||
{
|
||||
/// Get a reference to the `SortedLinkedList`, erasing the `N` const-generic.
|
||||
pub fn as_view(&self) -> &SortedLinkedListView<T, Idx, K> {
|
||||
S::as_view(self)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `Vec`, erasing the `N` const-generic.
|
||||
pub fn as_mut_view(&mut self) -> &mut SortedLinkedListView<T, Idx, K> {
|
||||
S::as_mut_view(self)
|
||||
}
|
||||
|
||||
/// Internal access helper
|
||||
#[inline(always)]
|
||||
fn node_at(&self, index: usize) -> &Node<T, Idx> {
|
||||
|
18
src/spsc.rs
18
src/spsc.rs
@ -162,18 +162,28 @@ impl<T, const N: usize> Queue<T, N> {
|
||||
N - 1
|
||||
}
|
||||
|
||||
/// Get a reference to the `Queue`, erasing the `N` const-generic.
|
||||
pub fn as_view(&self) -> &QueueView<T> {
|
||||
/// Used in `Storage` implementation
|
||||
pub(crate) fn as_view_private(&self) -> &QueueView<T> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `Queue`, erasing the `N` const-generic.
|
||||
pub fn as_mut_view(&mut self) -> &mut QueueView<T> {
|
||||
/// Used in `Storage` implementation
|
||||
pub(crate) fn as_mut_view_private(&mut self) -> &mut QueueView<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S: Storage> QueueInner<T, S> {
|
||||
/// Get a reference to the `Queue`, erasing the `N` const-generic.
|
||||
pub fn as_view(&self) -> &QueueView<T> {
|
||||
S::as_queue_view(self)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `Queue`, erasing the `N` const-generic.
|
||||
pub fn as_mut_view(&mut self) -> &mut QueueView<T> {
|
||||
S::as_mut_queue_view(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn increment(&self, val: usize) -> usize {
|
||||
(val + 1) % self.n()
|
||||
|
149
src/storage.rs
149
src/storage.rs
@ -2,6 +2,20 @@
|
||||
|
||||
use core::borrow::{Borrow, BorrowMut};
|
||||
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
target_has_atomic = "ptr",
|
||||
has_atomic_load_store
|
||||
))]
|
||||
use crate::spsc;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
all(feature = "mpmc_large", target_has_atomic = "ptr"),
|
||||
all(not(feature = "mpmc_large"), target_has_atomic = "8")
|
||||
))]
|
||||
use crate::mpmc::{MpMcQueue, MpMcQueueInner, MpMcQueueView};
|
||||
|
||||
pub(crate) trait SealedStorage {
|
||||
type Buffer<T>: ?Sized + Borrow<[T]> + BorrowMut<[T]>;
|
||||
/// Obtain the length of the buffer
|
||||
@ -10,6 +24,42 @@ pub(crate) trait SealedStorage {
|
||||
/// Obtain access to the first element of the buffer
|
||||
#[allow(unused)]
|
||||
fn as_ptr<T>(this: *mut Self::Buffer<T>) -> *mut T;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
all(feature = "mpmc_large", target_has_atomic = "ptr"),
|
||||
all(not(feature = "mpmc_large"), target_has_atomic = "8")
|
||||
))]
|
||||
fn as_mpmc_view<T>(this: &MpMcQueueInner<T, Self>) -> &MpMcQueueView<T>
|
||||
where
|
||||
Self: Storage + Sized;
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
all(feature = "mpmc_large", target_has_atomic = "ptr"),
|
||||
all(not(feature = "mpmc_large"), target_has_atomic = "8")
|
||||
))]
|
||||
fn as_mpmc_mut_view<T>(this: &mut MpMcQueueInner<T, Self>) -> &mut MpMcQueueView<T>
|
||||
where
|
||||
Self: Storage + Sized;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
target_has_atomic = "ptr",
|
||||
has_atomic_load_store
|
||||
))]
|
||||
/// Convert a `Queue` to a `QueueView`
|
||||
fn as_queue_view<T>(this: &spsc::QueueInner<T, Self>) -> &spsc::QueueView<T>
|
||||
where
|
||||
Self: Storage + Sized;
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
target_has_atomic = "ptr",
|
||||
has_atomic_load_store
|
||||
))]
|
||||
/// Convert a `Queue` to a `QueueView`
|
||||
fn as_mut_queue_view<T>(this: &mut spsc::QueueInner<T, Self>) -> &mut spsc::QueueView<T>
|
||||
where
|
||||
Self: Storage + Sized;
|
||||
}
|
||||
|
||||
/// Trait defining how data for a container is stored.
|
||||
@ -45,6 +95,56 @@ impl<const N: usize> SealedStorage for OwnedStorage<N> {
|
||||
fn as_ptr<T>(this: *mut Self::Buffer<T>) -> *mut T {
|
||||
this.cast()
|
||||
}
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
all(feature = "mpmc_large", target_has_atomic = "ptr"),
|
||||
all(not(feature = "mpmc_large"), target_has_atomic = "8")
|
||||
))]
|
||||
fn as_mpmc_view<T>(this: &MpMcQueue<T, N>) -> &MpMcQueueView<T>
|
||||
where
|
||||
Self: Storage + Sized,
|
||||
{
|
||||
// Fails to compile without the indirection
|
||||
this.as_view_private()
|
||||
}
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
all(feature = "mpmc_large", target_has_atomic = "ptr"),
|
||||
all(not(feature = "mpmc_large"), target_has_atomic = "8")
|
||||
))]
|
||||
fn as_mpmc_mut_view<T>(this: &mut MpMcQueue<T, N>) -> &mut MpMcQueueView<T>
|
||||
where
|
||||
Self: Storage + Sized,
|
||||
{
|
||||
// Fails to compile without the indirection
|
||||
this.as_view_mut_private()
|
||||
}
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
target_has_atomic = "ptr",
|
||||
has_atomic_load_store
|
||||
))]
|
||||
/// Convert a `Queue` to a `QueueView`
|
||||
fn as_queue_view<T>(this: &spsc::QueueInner<T, Self>) -> &spsc::QueueView<T>
|
||||
where
|
||||
Self: Storage + Sized,
|
||||
{
|
||||
// Fails to compile without the indirection
|
||||
this.as_view_private()
|
||||
}
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
target_has_atomic = "ptr",
|
||||
has_atomic_load_store
|
||||
))]
|
||||
/// Convert a `Queue` to a `QueueView`
|
||||
fn as_mut_queue_view<T>(this: &mut spsc::QueueInner<T, Self>) -> &mut spsc::QueueView<T>
|
||||
where
|
||||
Self: Storage + Sized,
|
||||
{
|
||||
// Fails to compile without the indirection
|
||||
this.as_mut_view_private()
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of [`Storage`] that stores the data in an unsized `[T]`.
|
||||
@ -59,4 +159,53 @@ impl SealedStorage for ViewStorage {
|
||||
fn as_ptr<T>(this: *mut Self::Buffer<T>) -> *mut T {
|
||||
this.cast()
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
all(feature = "mpmc_large", target_has_atomic = "ptr"),
|
||||
all(not(feature = "mpmc_large"), target_has_atomic = "8")
|
||||
))]
|
||||
fn as_mpmc_view<T>(this: &MpMcQueueInner<T, Self>) -> &MpMcQueueView<T>
|
||||
where
|
||||
Self: Storage + Sized,
|
||||
{
|
||||
this
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
all(feature = "mpmc_large", target_has_atomic = "ptr"),
|
||||
all(not(feature = "mpmc_large"), target_has_atomic = "8")
|
||||
))]
|
||||
fn as_mpmc_mut_view<T>(this: &mut MpMcQueueInner<T, Self>) -> &mut MpMcQueueView<T>
|
||||
where
|
||||
Self: Storage + Sized,
|
||||
{
|
||||
this
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
target_has_atomic = "ptr",
|
||||
has_atomic_load_store
|
||||
))]
|
||||
/// Convert a `Queue` to a `QueueView`
|
||||
fn as_queue_view<T>(this: &spsc::QueueInner<T, Self>) -> &spsc::QueueView<T>
|
||||
where
|
||||
Self: Storage + Sized,
|
||||
{
|
||||
this
|
||||
}
|
||||
#[cfg(any(
|
||||
feature = "portable-atomic",
|
||||
target_has_atomic = "ptr",
|
||||
has_atomic_load_store
|
||||
))]
|
||||
/// Convert a `Queue` to a `QueueView`
|
||||
fn as_mut_queue_view<T>(this: &mut spsc::QueueInner<T, Self>) -> &mut spsc::QueueView<T>
|
||||
where
|
||||
Self: Storage + Sized,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use core::{
|
||||
str::{self, Utf8Error},
|
||||
};
|
||||
|
||||
use crate::vec::{OwnedVecStorage, Vec, VecInner, VecStorage, ViewVecStorage};
|
||||
use crate::vec::{OwnedVecStorage, Vec, VecInner, ViewVecStorage};
|
||||
use crate::CapacityError;
|
||||
|
||||
mod drain;
|
||||
@ -47,84 +47,98 @@ impl From<CapacityError> for FromUtf16Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// Base struct for [`String`] and [`StringView`], generic over the [`VecStorage`].
|
||||
mod storage {
|
||||
use super::{StringInner, StringView};
|
||||
use crate::vec::{OwnedVecStorage, VecStorage, ViewVecStorage};
|
||||
|
||||
/// Trait defining how data for a String is stored.
|
||||
///
|
||||
/// There's two implementations available:
|
||||
///
|
||||
/// - [`OwnedStorage`]: stores the data in an array whose size is known at compile time.
|
||||
/// - [`ViewStorage`]: stores the data in an unsized slice
|
||||
///
|
||||
/// This allows [`String`] to be generic over either sized or unsized storage. The [`string`](super)
|
||||
/// module contains a [`StringInner`] struct that's generic on [`StringStorage`],
|
||||
/// and two type aliases for convenience:
|
||||
///
|
||||
/// - [`String<N>`](crate::string::String) = `StringInner<OwnedStorage<u8, N>>`
|
||||
/// - [`StringView<T>`](crate::string::StringView) = `StringInner<ViewStorage<u8>>`
|
||||
///
|
||||
/// `String` can be unsized into `StrinsgView`, either by unsizing coercions such as `&mut String -> &mut StringView` or
|
||||
/// `Box<String> -> Box<StringView>`, or explicitly with [`.as_view()`](crate::string::String::as_view) or [`.as_mut_view()`](crate::string::String::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.
|
||||
///
|
||||
/// [`StringInner`]: super::StringInner
|
||||
/// [`String`]: super::String
|
||||
/// [`OwnedStorage`]: super::OwnedStorage
|
||||
/// [`ViewStorage`]: super::ViewStorage
|
||||
pub trait StringStorage: StringStorageSealed {}
|
||||
pub trait StringStorageSealed: VecStorage<u8> {
|
||||
fn as_string_view(this: &StringInner<Self>) -> &StringView
|
||||
where
|
||||
Self: StringStorage;
|
||||
fn as_string_mut_view(this: &mut StringInner<Self>) -> &mut StringView
|
||||
where
|
||||
Self: StringStorage;
|
||||
}
|
||||
|
||||
impl<const N: usize> StringStorage for OwnedVecStorage<u8, N> {}
|
||||
impl<const N: usize> StringStorageSealed for OwnedVecStorage<u8, N> {
|
||||
fn as_string_view(this: &StringInner<Self>) -> &StringView
|
||||
where
|
||||
Self: StringStorage,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_string_mut_view(this: &mut StringInner<Self>) -> &mut StringView
|
||||
where
|
||||
Self: StringStorage,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl StringStorage for ViewVecStorage<u8> {}
|
||||
|
||||
impl StringStorageSealed for ViewVecStorage<u8> {
|
||||
fn as_string_view(this: &StringInner<Self>) -> &StringView
|
||||
where
|
||||
Self: StringStorage,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_string_mut_view(this: &mut StringInner<Self>) -> &mut StringView
|
||||
where
|
||||
Self: StringStorage,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use storage::StringStorage;
|
||||
|
||||
/// Implementation of [`StringStorage`] that stores the data in an array whose size is known at compile time.
|
||||
pub type OwnedStorage<const N: usize> = OwnedVecStorage<u8, N>;
|
||||
/// Implementation of [`StringStorage`] that stores the data in an unsized slice.
|
||||
pub type ViewStorage = ViewVecStorage<u8>;
|
||||
|
||||
/// Base struct for [`String`] and [`StringView`], generic over the [`StringStorage`].
|
||||
///
|
||||
/// 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: VecStorage<u8> + ?Sized> {
|
||||
pub struct StringInner<S: StringStorage + ?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<OwnedVecStorage<u8, N>>;
|
||||
pub type String<const N: usize> = StringInner<OwnedStorage<N>>;
|
||||
|
||||
/// A dynamic capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
|
||||
pub type StringView = StringInner<ViewVecStorage<u8>>;
|
||||
|
||||
impl StringView {
|
||||
/// Removes the specified range from the string in bulk, returning all
|
||||
/// removed characters as an iterator.
|
||||
///
|
||||
/// The returned iterator keeps a mutable borrow on the string to optimize
|
||||
/// its implementation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the starting point or end point do not lie on a [`char`]
|
||||
/// boundary, or if they're out of bounds.
|
||||
///
|
||||
/// # Leaking
|
||||
///
|
||||
/// If the returned iterator goes out of scope without being dropped (due to
|
||||
/// [`core::mem::forget`], for example), the string may still contain a copy
|
||||
/// of any drained characters, or may have lost characters arbitrarily,
|
||||
/// including characters outside the range.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::String;
|
||||
///
|
||||
/// let mut s = String::<32>::try_from("α is alpha, β is beta").unwrap();
|
||||
/// let beta_offset = s.find('β').unwrap_or(s.len());
|
||||
///
|
||||
/// // Remove the range up until the β from the string
|
||||
/// let t: String<32> = s.drain(..beta_offset).collect();
|
||||
/// assert_eq!(t, "α is alpha, ");
|
||||
/// assert_eq!(s, "β is beta");
|
||||
///
|
||||
/// // A full range clears the string, like `clear()` does
|
||||
/// s.drain(..);
|
||||
/// assert_eq!(s, "");
|
||||
/// ```
|
||||
pub fn drain<R>(&mut self, range: R) -> Drain<'_>
|
||||
where
|
||||
R: RangeBounds<usize>,
|
||||
{
|
||||
// Memory safety
|
||||
//
|
||||
// The `String` version of `Drain` does not have the memory safety issues
|
||||
// of the `Vec` version. The data is just plain bytes.
|
||||
// Because the range removal happens in `Drop`, if the `Drain` iterator is leaked,
|
||||
// the removal will not happen.
|
||||
let Range { start, end } = crate::slice::range(range, ..self.len());
|
||||
assert!(self.is_char_boundary(start));
|
||||
assert!(self.is_char_boundary(end));
|
||||
|
||||
// Take out two simultaneous borrows. The &mut String won't be accessed
|
||||
// until iteration is over, in Drop.
|
||||
let self_ptr = self as *mut _;
|
||||
// SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks.
|
||||
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
|
||||
|
||||
Drain {
|
||||
start,
|
||||
end,
|
||||
iter: chars_iter,
|
||||
string: self_ptr,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type StringView = StringInner<ViewStorage>;
|
||||
|
||||
impl<const N: usize> String<N> {
|
||||
/// Constructs a new, empty `String` with a fixed capacity of `N` bytes.
|
||||
@ -268,49 +282,9 @@ impl<const N: usize> String<N> {
|
||||
pub fn into_bytes(self) -> Vec<u8, N> {
|
||||
self.vec
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the `String`, erasing the `N` const-generic.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::string::{String, StringView};
|
||||
/// let s: String<10> = String::try_from("hello").unwrap();
|
||||
/// let view: &StringView = s.as_view();
|
||||
/// ```
|
||||
///
|
||||
/// It is often preferable to do the same through type coerction, since `String<N>` implements `Unsize<StringView>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::string::{String, StringView};
|
||||
/// let s: String<10> = String::try_from("hello").unwrap();
|
||||
/// let view: &StringView = &s;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_view(&self) -> &StringView {
|
||||
self
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `String`, erasing the `N` const-generic.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::string::{String, StringView};
|
||||
/// let mut s: String<10> = String::try_from("hello").unwrap();
|
||||
/// let view: &mut StringView = s.as_mut_view();
|
||||
/// ```
|
||||
///
|
||||
/// It is often preferable to do the same through type coerction, since `String<N>` implements `Unsize<StringView>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::string::{String, StringView};
|
||||
/// let mut s: String<10> = String::try_from("hello").unwrap();
|
||||
/// let view: &mut StringView = &mut s;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut_view(&mut self) -> &mut StringView {
|
||||
self
|
||||
}
|
||||
|
||||
impl<S: StringStorage + ?Sized> StringInner<S> {
|
||||
/// Removes the specified range from the string in bulk, returning all
|
||||
/// removed characters as an iterator.
|
||||
///
|
||||
@ -350,11 +324,72 @@ impl<const N: usize> String<N> {
|
||||
where
|
||||
R: RangeBounds<usize>,
|
||||
{
|
||||
self.as_mut_view().drain(range)
|
||||
}
|
||||
}
|
||||
// Memory safety
|
||||
//
|
||||
// The `String` version of `Drain` does not have the memory safety issues
|
||||
// of the `Vec` version. The data is just plain bytes.
|
||||
// Because the range removal happens in `Drop`, if the `Drain` iterator is leaked,
|
||||
// the removal will not happen.
|
||||
let Range { start, end } = crate::slice::range(range, ..self.len());
|
||||
assert!(self.is_char_boundary(start));
|
||||
assert!(self.is_char_boundary(end));
|
||||
|
||||
// Take out two simultaneous borrows. The &mut String won't be accessed
|
||||
// until iteration is over, in Drop.
|
||||
let self_ptr = self.as_mut_view() as *mut _;
|
||||
// SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks.
|
||||
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
|
||||
|
||||
Drain {
|
||||
start,
|
||||
end,
|
||||
iter: chars_iter,
|
||||
string: self_ptr,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the `String`, erasing the `N` const-generic.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::string::{String, StringView};
|
||||
/// let s: String<10> = String::try_from("hello").unwrap();
|
||||
/// let view: &StringView = s.as_view();
|
||||
/// ```
|
||||
///
|
||||
/// It is often preferable to do the same through type coerction, since `String<N>` implements `Unsize<StringView>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::string::{String, StringView};
|
||||
/// let s: String<10> = String::try_from("hello").unwrap();
|
||||
/// let view: &StringView = &s;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_view(&self) -> &StringView {
|
||||
S::as_string_view(self)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `String`, erasing the `N` const-generic.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::string::{String, StringView};
|
||||
/// let mut s: String<10> = String::try_from("hello").unwrap();
|
||||
/// let view: &mut StringView = s.as_mut_view();
|
||||
/// ```
|
||||
///
|
||||
/// It is often preferable to do the same through type coerction, since `String<N>` implements `Unsize<StringView>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::string::{String, StringView};
|
||||
/// let mut s: String<10> = String::try_from("hello").unwrap();
|
||||
/// let view: &mut StringView = &mut s;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut_view(&mut self) -> &mut StringView {
|
||||
S::as_string_mut_view(self)
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> StringInner<S> {
|
||||
/// Extracts a string slice containing the entire string.
|
||||
///
|
||||
/// # Examples
|
||||
@ -694,26 +729,26 @@ impl<const N: usize> Clone for String<N> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> fmt::Debug for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> fmt::Debug for StringInner<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
<str as fmt::Debug>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> fmt::Display for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> fmt::Display for StringInner<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
<str as fmt::Display>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> hash::Hash for StringInner<S> {
|
||||
impl<S: StringStorage + ?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: VecStorage<u8> + ?Sized> fmt::Write for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> fmt::Write for StringInner<S> {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
self.push_str(s).map_err(|_| fmt::Error)
|
||||
}
|
||||
@ -723,7 +758,7 @@ impl<S: VecStorage<u8> + ?Sized> fmt::Write for StringInner<S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> ops::Deref for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> ops::Deref for StringInner<S> {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &str {
|
||||
@ -731,38 +766,38 @@ impl<S: VecStorage<u8> + ?Sized> ops::Deref for StringInner<S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> ops::DerefMut for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> ops::DerefMut for StringInner<S> {
|
||||
fn deref_mut(&mut self) -> &mut str {
|
||||
self.as_mut_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> borrow::Borrow<str> for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> borrow::Borrow<str> for StringInner<S> {
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
impl<S: VecStorage<u8> + ?Sized> borrow::BorrowMut<str> for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> borrow::BorrowMut<str> for StringInner<S> {
|
||||
fn borrow_mut(&mut self) -> &mut str {
|
||||
self.as_mut_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> AsRef<str> for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> AsRef<str> for StringInner<S> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> AsRef<[u8]> for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> AsRef<[u8]> for StringInner<S> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S1: VecStorage<u8> + ?Sized, S2: VecStorage<u8> + ?Sized> PartialEq<StringInner<S1>>
|
||||
impl<S1: StringStorage + ?Sized, S2: StringStorage + ?Sized> PartialEq<StringInner<S1>>
|
||||
for StringInner<S2>
|
||||
{
|
||||
fn eq(&self, rhs: &StringInner<S1>) -> bool {
|
||||
@ -771,7 +806,7 @@ impl<S1: VecStorage<u8> + ?Sized, S2: VecStorage<u8> + ?Sized> PartialEq<StringI
|
||||
}
|
||||
|
||||
// String<N> == str
|
||||
impl<S: VecStorage<u8> + ?Sized> PartialEq<str> for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> PartialEq<str> for StringInner<S> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
str::eq(self, other)
|
||||
@ -779,7 +814,7 @@ impl<S: VecStorage<u8> + ?Sized> PartialEq<str> for StringInner<S> {
|
||||
}
|
||||
|
||||
// String<N> == &'str
|
||||
impl<S: VecStorage<u8> + ?Sized> PartialEq<&str> for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> PartialEq<&str> for StringInner<S> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
str::eq(self, &other[..])
|
||||
@ -787,7 +822,7 @@ impl<S: VecStorage<u8> + ?Sized> PartialEq<&str> for StringInner<S> {
|
||||
}
|
||||
|
||||
// str == String<N>
|
||||
impl<S: VecStorage<u8> + ?Sized> PartialEq<StringInner<S>> for str {
|
||||
impl<S: StringStorage + ?Sized> PartialEq<StringInner<S>> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &StringInner<S>) -> bool {
|
||||
Self::eq(self, &other[..])
|
||||
@ -795,16 +830,16 @@ impl<S: VecStorage<u8> + ?Sized> PartialEq<StringInner<S>> for str {
|
||||
}
|
||||
|
||||
// &'str == String<N>
|
||||
impl<S: VecStorage<u8> + ?Sized> PartialEq<StringInner<S>> for &str {
|
||||
impl<S: StringStorage + ?Sized> PartialEq<StringInner<S>> for &str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &StringInner<S>) -> bool {
|
||||
str::eq(self, &other[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> Eq for StringInner<S> {}
|
||||
impl<S: StringStorage + ?Sized> Eq for StringInner<S> {}
|
||||
|
||||
impl<S1: VecStorage<u8> + ?Sized, S2: VecStorage<u8> + ?Sized> PartialOrd<StringInner<S1>>
|
||||
impl<S1: StringStorage + ?Sized, S2: StringStorage + ?Sized> PartialOrd<StringInner<S1>>
|
||||
for StringInner<S2>
|
||||
{
|
||||
#[inline]
|
||||
@ -813,7 +848,7 @@ impl<S1: VecStorage<u8> + ?Sized, S2: VecStorage<u8> + ?Sized> PartialOrd<String
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> Ord for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> Ord for StringInner<S> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
Ord::cmp(&**self, &**other)
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::{
|
||||
string::StringInner,
|
||||
string::{StringInner, StringStorage},
|
||||
vec::{VecInner, VecStorage},
|
||||
CapacityError,
|
||||
};
|
||||
use ufmt_write::uWrite;
|
||||
|
||||
impl<S: VecStorage<u8> + ?Sized> uWrite for StringInner<S> {
|
||||
impl<S: StringStorage + ?Sized> uWrite for StringInner<S> {
|
||||
type Error = CapacityError;
|
||||
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
|
||||
self.push_str(s)
|
||||
|
237
src/vec/mod.rs
237
src/vec/mod.rs
@ -18,6 +18,13 @@ mod drain;
|
||||
mod storage {
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::{
|
||||
binary_heap::{BinaryHeapInner, BinaryHeapView},
|
||||
deque::{DequeInner, DequeView},
|
||||
};
|
||||
|
||||
use super::{VecInner, VecView};
|
||||
|
||||
/// Trait defining how data for a container is stored.
|
||||
///
|
||||
/// There's two implementations available:
|
||||
@ -48,6 +55,29 @@ mod storage {
|
||||
// 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>];
|
||||
|
||||
fn as_vec_view(this: &VecInner<T, Self>) -> &VecView<T>
|
||||
where
|
||||
Self: VecStorage<T>;
|
||||
fn as_vec_mut_view(this: &mut VecInner<T, Self>) -> &mut VecView<T>
|
||||
where
|
||||
Self: VecStorage<T>;
|
||||
|
||||
fn as_binary_heap_view<K>(this: &BinaryHeapInner<T, K, Self>) -> &BinaryHeapView<T, K>
|
||||
where
|
||||
Self: VecStorage<T>;
|
||||
fn as_binary_heap_mut_view<K>(
|
||||
this: &mut BinaryHeapInner<T, K, Self>,
|
||||
) -> &mut BinaryHeapView<T, K>
|
||||
where
|
||||
Self: VecStorage<T>;
|
||||
|
||||
fn as_deque_view(this: &DequeInner<T, Self>) -> &DequeView<T>
|
||||
where
|
||||
Self: VecStorage<T>;
|
||||
fn as_deque_mut_view(this: &mut DequeInner<T, Self>) -> &mut DequeView<T>
|
||||
where
|
||||
Self: VecStorage<T>;
|
||||
}
|
||||
|
||||
// One sealed layer of indirection to hide the internal details (The MaybeUninit).
|
||||
@ -67,6 +97,46 @@ mod storage {
|
||||
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>] {
|
||||
&mut self.buffer
|
||||
}
|
||||
|
||||
fn as_vec_view(this: &VecInner<T, Self>) -> &VecView<T>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_vec_mut_view(this: &mut VecInner<T, Self>) -> &mut VecView<T>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
|
||||
fn as_binary_heap_view<K>(this: &BinaryHeapInner<T, K, Self>) -> &BinaryHeapView<T, K>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_binary_heap_mut_view<K>(
|
||||
this: &mut BinaryHeapInner<T, K, Self>,
|
||||
) -> &mut BinaryHeapView<T, K>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_deque_view(this: &DequeInner<T, Self>) -> &DequeView<T>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_deque_mut_view(this: &mut DequeInner<T, Self>) -> &mut DequeView<T>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
impl<T, const N: usize> VecStorage<T> for OwnedVecStorage<T, N> {}
|
||||
|
||||
@ -77,6 +147,46 @@ mod storage {
|
||||
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>] {
|
||||
&mut self.buffer
|
||||
}
|
||||
|
||||
fn as_vec_view(this: &VecInner<T, Self>) -> &VecView<T>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_vec_mut_view(this: &mut VecInner<T, Self>) -> &mut VecView<T>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
|
||||
fn as_binary_heap_view<K>(this: &BinaryHeapInner<T, K, Self>) -> &BinaryHeapView<T, K>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_binary_heap_mut_view<K>(
|
||||
this: &mut BinaryHeapInner<T, K, Self>,
|
||||
) -> &mut BinaryHeapView<T, K>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_deque_view(this: &DequeInner<T, Self>) -> &DequeView<T>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
fn as_deque_mut_view(this: &mut DequeInner<T, Self>) -> &mut DequeView<T>
|
||||
where
|
||||
Self: VecStorage<T>,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
impl<T> VecStorage<T> for ViewVecStorage<T> {}
|
||||
}
|
||||
@ -282,89 +392,9 @@ impl<T, const N: usize> Vec<T, N> {
|
||||
}
|
||||
new
|
||||
}
|
||||
|
||||
/// Get a reference to the `Vec`, erasing the `N` const-generic.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::{Vec, VecView};
|
||||
/// let vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
|
||||
/// let view: &VecView<u8> = vec.as_view();
|
||||
/// ```
|
||||
///
|
||||
/// It is often preferable to do the same through type coerction, since `Vec<T, N>` implements `Unsize<VecView<T>>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::{Vec, VecView};
|
||||
/// let vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
|
||||
/// let view: &VecView<u8> = &vec;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn as_view(&self) -> &VecView<T> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `Vec`, erasing the `N` const-generic.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::{Vec, VecView};
|
||||
/// let mut vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
|
||||
/// let view: &mut VecView<u8> = vec.as_mut_view();
|
||||
/// ```
|
||||
///
|
||||
/// It is often preferable to do the same through type coerction, since `Vec<T, N>` implements `Unsize<VecView<T>>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::{Vec, VecView};
|
||||
/// let mut vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
|
||||
/// let view: &mut VecView<u8> = &mut vec;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut_view(&mut self) -> &mut VecView<T> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Removes the specified range from the vector in bulk, returning all
|
||||
/// removed elements as an iterator. If the iterator is dropped before
|
||||
/// being fully consumed, it drops the remaining removed elements.
|
||||
///
|
||||
/// The returned iterator keeps a mutable borrow on the vector to optimize
|
||||
/// its implementation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the starting point is greater than the end point or if
|
||||
/// the end point is greater than the length of the vector.
|
||||
///
|
||||
/// # Leaking
|
||||
///
|
||||
/// If the returned iterator goes out of scope without being dropped (due to
|
||||
/// [`mem::forget`], for example), the vector may have lost and leaked
|
||||
/// elements arbitrarily, including elements outside the range.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use heapless::Vec;
|
||||
///
|
||||
/// let mut v = Vec::<_, 8>::from_array([1, 2, 3]);
|
||||
/// let u: Vec<_, 8> = v.drain(1..).collect();
|
||||
/// assert_eq!(v, &[1]);
|
||||
/// assert_eq!(u, &[2, 3]);
|
||||
///
|
||||
/// // A full range clears the vector, like `clear()` does.
|
||||
/// v.drain(..);
|
||||
/// assert_eq!(v, &[]);
|
||||
/// ```
|
||||
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
|
||||
where
|
||||
R: RangeBounds<usize>,
|
||||
{
|
||||
self.as_mut_view().drain(range)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VecView<T> {
|
||||
impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
|
||||
/// Removes the specified range from the vector in bulk, returning all
|
||||
/// removed elements as an iterator. If the iterator is dropped before
|
||||
/// being fully consumed, it drops the remaining removed elements.
|
||||
@ -417,7 +447,7 @@ impl<T> VecView<T> {
|
||||
unsafe {
|
||||
// Set `self.vec` length's to `start`, to be safe in case `Drain` is leaked.
|
||||
self.set_len(start);
|
||||
let vec = NonNull::from(self);
|
||||
let vec = NonNull::from(self.as_mut_view());
|
||||
let range_slice = slice::from_raw_parts(vec.as_ref().as_ptr().add(start), end - start);
|
||||
Drain {
|
||||
tail_start: end,
|
||||
@ -427,9 +457,48 @@ impl<T> VecView<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
|
||||
/// Get a reference to the `Vec`, erasing the `N` const-generic.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::{Vec, VecView};
|
||||
/// let vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
|
||||
/// let view: &VecView<u8> = vec.as_view();
|
||||
/// ```
|
||||
///
|
||||
/// It is often preferable to do the same through type coerction, since `Vec<T, N>` implements `Unsize<VecView<T>>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::{Vec, VecView};
|
||||
/// let vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
|
||||
/// let view: &VecView<u8> = &vec;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_view(&self) -> &VecView<T> {
|
||||
S::as_vec_view(self)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the `Vec`, erasing the `N` const-generic.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::{Vec, VecView};
|
||||
/// let mut vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
|
||||
/// let view: &mut VecView<u8> = vec.as_mut_view();
|
||||
/// ```
|
||||
///
|
||||
/// It is often preferable to do the same through type coerction, since `Vec<T, N>` implements `Unsize<VecView<T>>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use heapless::{Vec, VecView};
|
||||
/// let mut vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
|
||||
/// let view: &mut VecView<u8> = &mut vec;
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut_view(&mut self) -> &mut VecView<T> {
|
||||
S::as_vec_mut_view(self)
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the vector’s buffer.
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
self.buffer.borrow().as_ptr().cast::<T>()
|
||||
|
Loading…
x
Reference in New Issue
Block a user