diff --git a/src/binary_heap.rs b/src/binary_heap.rs index f7239b47..b15ec959 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -184,14 +184,16 @@ impl BinaryHeap { pub fn into_vec(self) -> Vec { self.data } +} +impl> BinaryHeapInner { /// Get a reference to the `BinaryHeap`, erasing the `N` const-generic. pub fn as_view(&self) -> &BinaryHeapView { - 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 { - self + S::as_binary_heap_mut_view(self) } } diff --git a/src/defmt.rs b/src/defmt.rs index f59ddb9d..9c4d2779 100644 --- a/src/defmt.rs +++ b/src/defmt.rs @@ -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 + ?Sized> defmt::Format for StringInner +impl defmt::Format for StringInner where u8: defmt::Format, { diff --git a/src/deque.rs b/src/deque.rs index b170de1f..63e0f510 100644 --- a/src/deque.rs +++ b/src/deque.rs @@ -186,19 +186,19 @@ impl Deque { self.back - self.front } } +} +impl + ?Sized> DequeInner { /// Get a reference to the `Deque`, erasing the `N` const-generic. pub fn as_view(&self) -> &DequeView { - 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 { - self + S::as_deque_mut_view(self) } -} -impl + ?Sized> DequeInner { /// Returns the maximum number of elements the deque can hold. pub fn storage_capacity(&self) -> usize { self.buffer.borrow().len() diff --git a/src/histbuf.rs b/src/histbuf.rs index 9d105ed6..cc4b4922 100644 --- a/src/histbuf.rs +++ b/src/histbuf.rs @@ -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]; fn borrow_mut(&mut self) -> &mut [MaybeUninit]; + fn as_hist_buf_view(this: &HistoryBufferInner) -> &HistoryBufferView + where + Self: HistBufStorage; + fn as_hist_buf_mut_view( + this: &mut HistoryBufferInner, + ) -> &mut HistoryBufferView + where + Self: HistBufStorage; } // 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] { &mut self.buffer } + fn as_hist_buf_view(this: &HistoryBufferInner) -> &HistoryBufferView + where + Self: HistBufStorage, + { + this + } + fn as_hist_buf_mut_view(this: &mut HistoryBufferInner) -> &mut HistoryBufferView + where + Self: HistBufStorage, + { + this + } } impl HistBufStorage for OwnedHistBufStorage {} @@ -101,6 +123,18 @@ mod storage { fn borrow_mut(&mut self) -> &mut [MaybeUninit] { &mut self.buffer } + fn as_hist_buf_view(this: &HistoryBufferInner) -> &HistoryBufferView + where + Self: HistBufStorage, + { + this + } + fn as_hist_buf_mut_view(this: &mut HistoryBufferInner) -> &mut HistoryBufferView + where + Self: HistBufStorage, + { + this + } } impl HistBufStorage for ViewHistBufStorage {} } @@ -221,18 +255,6 @@ impl HistoryBuffer { filled: false, } } - - /// Get a reference to the `HistoryBuffer`, erasing the `N` const-generic. - #[inline] - pub const fn as_view(&self) -> &HistoryBufferView { - self - } - - /// Get a mutable reference to the `HistoryBuffer`, erasing the `N` const-generic. - #[inline] - pub fn as_mut_view(&mut self) -> &mut HistoryBufferView { - self - } } impl HistoryBuffer @@ -264,6 +286,17 @@ where } } impl + ?Sized> HistoryBufferInner { + /// Get a reference to the `HistoryBuffer`, erasing the `N` const-generic. + #[inline] + pub fn as_view(&self) -> &HistoryBufferView { + 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 { + 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 diff --git a/src/lib.rs b/src/lib.rs index f3ef35c6..b5fe9a71 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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")] diff --git a/src/linear_map.rs b/src/linear_map.rs index 3b38fced..d4e137cc 100644 --- a/src/linear_map.rs +++ b/src/linear_map.rs @@ -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`](crate::linear_map::LinearMap) = `LinearMapInner>` + /// - [`LinearMapView`](crate::linear_map::LinearMapView) = `LinearMapInner>` + /// + /// `LinearMap` can be unsized into `StrinsgView`, either by unsizing coercions such as `&mut LinearMap -> &mut LinearMapView` or + /// `Box -> Box`, 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: LinearMapStorageSealed {} + pub trait LinearMapStorageSealed: VecStorage<(K, V)> { + fn as_linear_map_view(this: &LinearMapInner) -> &LinearMapView + where + Self: LinearMapStorage; + fn as_linear_map_mut_view( + this: &mut LinearMapInner, + ) -> &mut LinearMapView + where + Self: LinearMapStorage; + } + + impl LinearMapStorage for OwnedVecStorage<(K, V), N> {} + impl LinearMapStorageSealed for OwnedVecStorage<(K, V), N> { + fn as_linear_map_view(this: &LinearMapInner) -> &LinearMapView + where + Self: LinearMapStorage, + { + this + } + fn as_linear_map_mut_view(this: &mut LinearMapInner) -> &mut LinearMapView + where + Self: LinearMapStorage, + { + this + } + } + + impl LinearMapStorage for ViewVecStorage<(K, V)> {} + + impl LinearMapStorageSealed for ViewVecStorage<(K, V)> { + fn as_linear_map_view(this: &LinearMapInner) -> &LinearMapView + where + Self: LinearMapStorage, + { + this + } + fn as_linear_map_mut_view(this: &mut LinearMapInner) -> &mut LinearMapView + where + Self: LinearMapStorage, + { + 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 = OwnedVecStorage<(K, V), N>; +/// Implementation of [`LinearMapStorage`] that stores the data in an unsized slice. +pub type ViewStorage = ViewVecStorage<(K, V)>; /// Base struct for [`LinearMap`] and [`LinearMapView`] -pub struct LinearMapInner + ?Sized> { +pub struct LinearMapInner + ?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 = LinearMapInner>; +pub type LinearMap = LinearMapInner>; /// 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 = LinearMapInner>; +pub type LinearMapView = LinearMapInner>; impl LinearMap { /// Creates an empty `LinearMap`. @@ -38,22 +119,22 @@ impl LinearMap { pub const fn new() -> Self { Self { buffer: Vec::new() } } +} +impl + ?Sized> LinearMapInner +where + K: Eq, +{ /// Get a reference to the `LinearMap`, erasing the `N` const-generic. pub fn as_view(&self) -> &LinearMapView { - 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 { - self + S::as_linear_map_mut_view(self) } -} -impl + ?Sized> LinearMapInner -where - K: Eq, -{ /// Returns the number of elements that the map can hold. /// /// Computes in *O*(1) time. @@ -388,7 +469,7 @@ where } } -impl + ?Sized> ops::Index<&'_ Q> for LinearMapInner +impl + ?Sized> ops::Index<&'_ Q> for LinearMapInner where K: Borrow + Eq, Q: Eq + ?Sized, @@ -400,7 +481,7 @@ where } } -impl + ?Sized> ops::IndexMut<&'_ Q> for LinearMapInner +impl + ?Sized> ops::IndexMut<&'_ Q> for LinearMapInner where K: Borrow + Eq, Q: Eq + ?Sized, @@ -431,7 +512,7 @@ where } } -impl + ?Sized> fmt::Debug for LinearMapInner +impl + ?Sized> fmt::Debug for LinearMapInner 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 +impl<'a, K, V, S: LinearMapStorage + ?Sized> IntoIterator for &'a LinearMapInner where K: Eq, { @@ -533,7 +614,7 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { } } -impl + ?Sized, S2: VecStorage<(K, V)> + ?Sized> +impl + ?Sized, S2: LinearMapStorage + ?Sized> PartialEq> for LinearMapInner where K: Eq, @@ -547,7 +628,7 @@ where } } -impl + ?Sized> Eq for LinearMapInner +impl + ?Sized> Eq for LinearMapInner where K: Eq, V: PartialEq, diff --git a/src/mpmc.rs b/src/mpmc.rs index 99f004e1..3541e170 100644 --- a/src/mpmc.rs +++ b/src/mpmc.rs @@ -173,6 +173,18 @@ impl MpMcQueue { enqueue_pos: AtomicTargetSize::new(0), } } + + /// Used in `Storage` implementation + pub(crate) fn as_view_private(&self) -> &MpMcQueueView { + self + } + /// Used in `Storage` implementation + pub(crate) fn as_view_mut_private(&mut self) -> &mut MpMcQueueView { + self + } +} + +impl MpMcQueueInner { /// Get a reference to the `MpMcQueue`, erasing the `N` const-generic. /// /// @@ -190,8 +202,8 @@ impl MpMcQueue { /// let view: &MpMcQueueView = &queue; /// ``` #[inline] - pub const fn as_view(&self) -> &MpMcQueueView { - self + pub fn as_view(&self) -> &MpMcQueueView { + S::as_mpmc_view(self) } /// Get a mutable reference to the `MpMcQueue`, erasing the `N` const-generic. @@ -211,11 +223,9 @@ impl MpMcQueue { /// ``` #[inline] pub fn as_mut_view(&mut self) -> &mut MpMcQueueView { - self + S::as_mpmc_mut_view(self) } -} -impl MpMcQueueInner { fn mask(&self) -> UintSize { (S::len(self.buffer.get()) - 1) as _ } diff --git a/src/ser.rs b/src/ser.rs index a1ee784f..26d2858e 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -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 + ?Sized> Serialize for LinearMapInner +impl + ?Sized> Serialize for LinearMapInner where K: Eq + Serialize, V: Serialize, @@ -135,7 +135,7 @@ where // String containers -impl + ?Sized> Serialize for StringInner { +impl Serialize for StringInner { fn serialize(&self, serializer: SER) -> Result where SER: Serializer, diff --git a/src/sorted_linked_list.rs b/src/sorted_linked_list.rs index 22f18880..60d2d325 100644 --- a/src/sorted_linked_list.rs +++ b/src/sorted_linked_list.rs @@ -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]; fn borrow_mut(&mut self) -> &mut [Node]; + fn as_view( + this: &SortedLinkedListInner, + ) -> &SortedLinkedListView + where + Idx: SortedLinkedListIndex, + Self: SortedLinkedListStorage; + fn as_mut_view( + this: &mut SortedLinkedListInner, + ) -> &mut SortedLinkedListView + where + Idx: SortedLinkedListIndex, + Self: SortedLinkedListStorage; } // 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] { &mut self.buffer } + fn as_view( + this: &SortedLinkedListInner, + ) -> &SortedLinkedListView + where + Self: SortedLinkedListStorage, + Idx: SortedLinkedListIndex, + { + this + } + fn as_mut_view( + this: &mut SortedLinkedListInner, + ) -> &mut SortedLinkedListView + where + Self: SortedLinkedListStorage, + Idx: SortedLinkedListIndex, + { + this + } } impl SortedLinkedListStorage for OwnedSortedLinkedListStorage @@ -101,6 +131,24 @@ mod storage { fn borrow_mut(&mut self) -> &mut [Node] { &mut self.buffer } + fn as_view( + this: &SortedLinkedListInner, + ) -> &SortedLinkedListView + where + Self: SortedLinkedListStorage, + Idx: SortedLinkedListIndex, + { + this + } + fn as_mut_view( + this: &mut SortedLinkedListInner, + ) -> &mut SortedLinkedListView + where + Self: SortedLinkedListStorage, + Idx: SortedLinkedListIndex, + { + this + } } impl SortedLinkedListStorage for ViewSortedLinkedListStorage {} } @@ -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 SortedLinkedList -where - Idx: SortedLinkedListIndex, -{ - /// Get a reference to the `SortedLinkedList`, erasing the `N` const-generic. - pub fn as_view(&self) -> &SortedLinkedListView { - self - } - - /// Get a mutable reference to the `Vec`, erasing the `N` const-generic. - pub fn as_mut_view(&mut self) -> &mut SortedLinkedListView { - self - } -} - impl SortedLinkedListInner where Idx: SortedLinkedListIndex, S: SortedLinkedListStorage + ?Sized, { + /// Get a reference to the `SortedLinkedList`, erasing the `N` const-generic. + pub fn as_view(&self) -> &SortedLinkedListView { + 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 { + S::as_mut_view(self) + } + /// Internal access helper #[inline(always)] fn node_at(&self, index: usize) -> &Node { diff --git a/src/spsc.rs b/src/spsc.rs index e00b5f78..fa989fe9 100644 --- a/src/spsc.rs +++ b/src/spsc.rs @@ -162,18 +162,28 @@ impl Queue { N - 1 } - /// Get a reference to the `Queue`, erasing the `N` const-generic. - pub fn as_view(&self) -> &QueueView { + /// Used in `Storage` implementation + pub(crate) fn as_view_private(&self) -> &QueueView { self } - /// Get a mutable reference to the `Queue`, erasing the `N` const-generic. - pub fn as_mut_view(&mut self) -> &mut QueueView { + /// Used in `Storage` implementation + pub(crate) fn as_mut_view_private(&mut self) -> &mut QueueView { self } } impl QueueInner { + /// Get a reference to the `Queue`, erasing the `N` const-generic. + pub fn as_view(&self) -> &QueueView { + 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 { + S::as_mut_queue_view(self) + } + #[inline] fn increment(&self, val: usize) -> usize { (val + 1) % self.n() diff --git a/src/storage.rs b/src/storage.rs index 2995dae1..b6b247fc 100644 --- a/src/storage.rs +++ b/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: ?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(this: *mut Self::Buffer) -> *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(this: &MpMcQueueInner) -> &MpMcQueueView + 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(this: &mut MpMcQueueInner) -> &mut MpMcQueueView + 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(this: &spsc::QueueInner) -> &spsc::QueueView + 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(this: &mut spsc::QueueInner) -> &mut spsc::QueueView + where + Self: Storage + Sized; } /// Trait defining how data for a container is stored. @@ -45,6 +95,56 @@ impl SealedStorage for OwnedStorage { fn as_ptr(this: *mut Self::Buffer) -> *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(this: &MpMcQueue) -> &MpMcQueueView + 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(this: &mut MpMcQueue) -> &mut MpMcQueueView + 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(this: &spsc::QueueInner) -> &spsc::QueueView + 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(this: &mut spsc::QueueInner) -> &mut spsc::QueueView + 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(this: *mut Self::Buffer) -> *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(this: &MpMcQueueInner) -> &MpMcQueueView + 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(this: &mut MpMcQueueInner) -> &mut MpMcQueueView + 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(this: &spsc::QueueInner) -> &spsc::QueueView + 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(this: &mut spsc::QueueInner) -> &mut spsc::QueueView + where + Self: Storage + Sized, + { + this + } } diff --git a/src/string/mod.rs b/src/string/mod.rs index b820ebca..1a5b968a 100644 --- a/src/string/mod.rs +++ b/src/string/mod.rs @@ -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 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`](crate::string::String) = `StringInner>` + /// - [`StringView`](crate::string::StringView) = `StringInner>` + /// + /// `String` can be unsized into `StrinsgView`, either by unsizing coercions such as `&mut String -> &mut StringView` or + /// `Box -> Box`, 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 { + fn as_string_view(this: &StringInner) -> &StringView + where + Self: StringStorage; + fn as_string_mut_view(this: &mut StringInner) -> &mut StringView + where + Self: StringStorage; + } + + impl StringStorage for OwnedVecStorage {} + impl StringStorageSealed for OwnedVecStorage { + fn as_string_view(this: &StringInner) -> &StringView + where + Self: StringStorage, + { + this + } + fn as_string_mut_view(this: &mut StringInner) -> &mut StringView + where + Self: StringStorage, + { + this + } + } + + impl StringStorage for ViewVecStorage {} + + impl StringStorageSealed for ViewVecStorage { + fn as_string_view(this: &StringInner) -> &StringView + where + Self: StringStorage, + { + this + } + fn as_string_mut_view(this: &mut StringInner) -> &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 = OwnedVecStorage; +/// Implementation of [`StringStorage`] that stores the data in an unsized slice. +pub type ViewStorage = ViewVecStorage; + +/// 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 + ?Sized> { +pub struct StringInner { vec: VecInner, } /// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html). -pub type String = StringInner>; +pub type String = StringInner>; /// A dynamic capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html). -pub type StringView = StringInner>; - -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(&mut self, range: R) -> Drain<'_> - where - R: RangeBounds, - { - // 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; impl String { /// Constructs a new, empty `String` with a fixed capacity of `N` bytes. @@ -268,49 +282,9 @@ impl String { pub fn into_bytes(self) -> Vec { 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` implements `Unsize`: - /// - /// ```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` implements `Unsize`: - /// - /// ```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 StringInner { /// Removes the specified range from the string in bulk, returning all /// removed characters as an iterator. /// @@ -350,11 +324,72 @@ impl String { where R: RangeBounds, { - 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` implements `Unsize`: + /// + /// ```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` implements `Unsize`: + /// + /// ```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 + ?Sized> StringInner { /// Extracts a string slice containing the entire string. /// /// # Examples @@ -694,26 +729,26 @@ impl Clone for String { } } -impl + ?Sized> fmt::Debug for StringInner { +impl fmt::Debug for StringInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ::fmt(self, f) } } -impl + ?Sized> fmt::Display for StringInner { +impl fmt::Display for StringInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ::fmt(self, f) } } -impl + ?Sized> hash::Hash for StringInner { +impl hash::Hash for StringInner { #[inline] fn hash(&self, hasher: &mut H) { ::hash(self, hasher); } } -impl + ?Sized> fmt::Write for StringInner { +impl fmt::Write for StringInner { fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { self.push_str(s).map_err(|_| fmt::Error) } @@ -723,7 +758,7 @@ impl + ?Sized> fmt::Write for StringInner { } } -impl + ?Sized> ops::Deref for StringInner { +impl ops::Deref for StringInner { type Target = str; fn deref(&self) -> &str { @@ -731,38 +766,38 @@ impl + ?Sized> ops::Deref for StringInner { } } -impl + ?Sized> ops::DerefMut for StringInner { +impl ops::DerefMut for StringInner { fn deref_mut(&mut self) -> &mut str { self.as_mut_str() } } -impl + ?Sized> borrow::Borrow for StringInner { +impl borrow::Borrow for StringInner { fn borrow(&self) -> &str { self.as_str() } } -impl + ?Sized> borrow::BorrowMut for StringInner { +impl borrow::BorrowMut for StringInner { fn borrow_mut(&mut self) -> &mut str { self.as_mut_str() } } -impl + ?Sized> AsRef for StringInner { +impl AsRef for StringInner { #[inline] fn as_ref(&self) -> &str { self } } -impl + ?Sized> AsRef<[u8]> for StringInner { +impl AsRef<[u8]> for StringInner { #[inline] fn as_ref(&self) -> &[u8] { self.as_bytes() } } -impl + ?Sized, S2: VecStorage + ?Sized> PartialEq> +impl PartialEq> for StringInner { fn eq(&self, rhs: &StringInner) -> bool { @@ -771,7 +806,7 @@ impl + ?Sized, S2: VecStorage + ?Sized> PartialEq == str -impl + ?Sized> PartialEq for StringInner { +impl PartialEq for StringInner { #[inline] fn eq(&self, other: &str) -> bool { str::eq(self, other) @@ -779,7 +814,7 @@ impl + ?Sized> PartialEq for StringInner { } // String == &'str -impl + ?Sized> PartialEq<&str> for StringInner { +impl PartialEq<&str> for StringInner { #[inline] fn eq(&self, other: &&str) -> bool { str::eq(self, &other[..]) @@ -787,7 +822,7 @@ impl + ?Sized> PartialEq<&str> for StringInner { } // str == String -impl + ?Sized> PartialEq> for str { +impl PartialEq> for str { #[inline] fn eq(&self, other: &StringInner) -> bool { Self::eq(self, &other[..]) @@ -795,16 +830,16 @@ impl + ?Sized> PartialEq> for str { } // &'str == String -impl + ?Sized> PartialEq> for &str { +impl PartialEq> for &str { #[inline] fn eq(&self, other: &StringInner) -> bool { str::eq(self, &other[..]) } } -impl + ?Sized> Eq for StringInner {} +impl Eq for StringInner {} -impl + ?Sized, S2: VecStorage + ?Sized> PartialOrd> +impl PartialOrd> for StringInner { #[inline] @@ -813,7 +848,7 @@ impl + ?Sized, S2: VecStorage + ?Sized> PartialOrd + ?Sized> Ord for StringInner { +impl Ord for StringInner { #[inline] fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(&**self, &**other) diff --git a/src/ufmt.rs b/src/ufmt.rs index 8ad19780..40ff32bd 100644 --- a/src/ufmt.rs +++ b/src/ufmt.rs @@ -1,11 +1,11 @@ use crate::{ - string::StringInner, + string::{StringInner, StringStorage}, vec::{VecInner, VecStorage}, CapacityError, }; use ufmt_write::uWrite; -impl + ?Sized> uWrite for StringInner { +impl uWrite for StringInner { type Error = CapacityError; fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { self.push_str(s) diff --git a/src/vec/mod.rs b/src/vec/mod.rs index d8ff1843..f570ecdf 100644 --- a/src/vec/mod.rs +++ b/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]; fn borrow_mut(&mut self) -> &mut [MaybeUninit]; + + fn as_vec_view(this: &VecInner) -> &VecView + where + Self: VecStorage; + fn as_vec_mut_view(this: &mut VecInner) -> &mut VecView + where + Self: VecStorage; + + fn as_binary_heap_view(this: &BinaryHeapInner) -> &BinaryHeapView + where + Self: VecStorage; + fn as_binary_heap_mut_view( + this: &mut BinaryHeapInner, + ) -> &mut BinaryHeapView + where + Self: VecStorage; + + fn as_deque_view(this: &DequeInner) -> &DequeView + where + Self: VecStorage; + fn as_deque_mut_view(this: &mut DequeInner) -> &mut DequeView + where + Self: VecStorage; } // 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] { &mut self.buffer } + + fn as_vec_view(this: &VecInner) -> &VecView + where + Self: VecStorage, + { + this + } + fn as_vec_mut_view(this: &mut VecInner) -> &mut VecView + where + Self: VecStorage, + { + this + } + + fn as_binary_heap_view(this: &BinaryHeapInner) -> &BinaryHeapView + where + Self: VecStorage, + { + this + } + fn as_binary_heap_mut_view( + this: &mut BinaryHeapInner, + ) -> &mut BinaryHeapView + where + Self: VecStorage, + { + this + } + fn as_deque_view(this: &DequeInner) -> &DequeView + where + Self: VecStorage, + { + this + } + fn as_deque_mut_view(this: &mut DequeInner) -> &mut DequeView + where + Self: VecStorage, + { + this + } } impl VecStorage for OwnedVecStorage {} @@ -77,6 +147,46 @@ mod storage { fn borrow_mut(&mut self) -> &mut [MaybeUninit] { &mut self.buffer } + + fn as_vec_view(this: &VecInner) -> &VecView + where + Self: VecStorage, + { + this + } + fn as_vec_mut_view(this: &mut VecInner) -> &mut VecView + where + Self: VecStorage, + { + this + } + + fn as_binary_heap_view(this: &BinaryHeapInner) -> &BinaryHeapView + where + Self: VecStorage, + { + this + } + fn as_binary_heap_mut_view( + this: &mut BinaryHeapInner, + ) -> &mut BinaryHeapView + where + Self: VecStorage, + { + this + } + fn as_deque_view(this: &DequeInner) -> &DequeView + where + Self: VecStorage, + { + this + } + fn as_deque_mut_view(this: &mut DequeInner) -> &mut DequeView + where + Self: VecStorage, + { + this + } } impl VecStorage for ViewVecStorage {} } @@ -282,89 +392,9 @@ impl Vec { } new } - - /// Get a reference to the `Vec`, erasing the `N` const-generic. - /// - /// - /// ```rust - /// # use heapless::{Vec, VecView}; - /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// let view: &VecView = vec.as_view(); - /// ``` - /// - /// It is often preferable to do the same through type coerction, since `Vec` implements `Unsize>`: - /// - /// ```rust - /// # use heapless::{Vec, VecView}; - /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// let view: &VecView = &vec; - /// ``` - #[inline] - pub const fn as_view(&self) -> &VecView { - self - } - - /// Get a mutable reference to the `Vec`, erasing the `N` const-generic. - /// - /// ```rust - /// # use heapless::{Vec, VecView}; - /// let mut vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// let view: &mut VecView = vec.as_mut_view(); - /// ``` - /// - /// It is often preferable to do the same through type coerction, since `Vec` implements `Unsize>`: - /// - /// ```rust - /// # use heapless::{Vec, VecView}; - /// let mut vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// let view: &mut VecView = &mut vec; - /// ``` - #[inline] - pub fn as_mut_view(&mut self) -> &mut VecView { - 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(&mut self, range: R) -> Drain<'_, T> - where - R: RangeBounds, - { - self.as_mut_view().drain(range) - } } -impl VecView { +impl + ?Sized> VecInner { /// 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 VecView { 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 VecView { } } } -} -impl + ?Sized> VecInner { + /// Get a reference to the `Vec`, erasing the `N` const-generic. + /// + /// + /// ```rust + /// # use heapless::{Vec, VecView}; + /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let view: &VecView = vec.as_view(); + /// ``` + /// + /// It is often preferable to do the same through type coerction, since `Vec` implements `Unsize>`: + /// + /// ```rust + /// # use heapless::{Vec, VecView}; + /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let view: &VecView = &vec; + /// ``` + #[inline] + pub fn as_view(&self) -> &VecView { + 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 = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let view: &mut VecView = vec.as_mut_view(); + /// ``` + /// + /// It is often preferable to do the same through type coerction, since `Vec` implements `Unsize>`: + /// + /// ```rust + /// # use heapless::{Vec, VecView}; + /// let mut vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let view: &mut VecView = &mut vec; + /// ``` + #[inline] + pub fn as_mut_view(&mut self) -> &mut VecView { + 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::()