Skip to content

Commit

Permalink
Implement a generic length parameter for Vec<T, N>
Browse files Browse the repository at this point in the history
  • Loading branch information
GnomedDev committed Jul 18, 2024
1 parent 1c47ffc commit 7f97b86
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 190 deletions.
4 changes: 2 additions & 2 deletions src/binary_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl private::Sealed for Min {}
/// struct if you want to write code that's generic over both.
pub struct BinaryHeapInner<T, K, S: Storage> {
pub(crate) _kind: PhantomData<K>,
pub(crate) data: VecInner<T, S>,
pub(crate) data: VecInner<T, usize, S>,
}

/// A priority queue implemented with a binary heap.
Expand Down Expand Up @@ -184,7 +184,7 @@ impl<T, K, const N: usize> BinaryHeap<T, K, N> {

impl<T, K, const N: usize> BinaryHeap<T, K, N> {
/// Returns the underlying `Vec<T,N>`. Order is arbitrary and time is *O*(1).
pub fn into_vec(self) -> Vec<T, N> {
pub fn into_vec(self) -> Vec<T, N, usize> {
self.data
}

Expand Down
4 changes: 2 additions & 2 deletions src/indexmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ macro_rules! probe_loop {
}

struct CoreMap<K, V, const N: usize> {
entries: Vec<Bucket<K, V>, N>,
entries: Vec<Bucket<K, V>, N, usize>,
indices: [Option<Pos>; N],
}

Expand Down Expand Up @@ -1298,7 +1298,7 @@ where

#[derive(Clone)]
pub struct IntoIter<K, V, const N: usize> {
entries: Vec<Bucket<K, V>, N>,
entries: Vec<Bucket<K, V>, N, usize>,
}

impl<K, V, const N: usize> Iterator for IntoIter<K, V, N> {
Expand Down
71 changes: 71 additions & 0 deletions src/len_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use core::{
fmt::{Debug, Display},
ops::{Add, AddAssign, Sub, SubAssign},
};

macro_rules! impl_lentype {
($($LenT:ty),*) => {$(
impl LenType for $LenT {
const ZERO: Self = 0;
const ONE: Self = 1;
const MAX: usize = Self::MAX as _;
}
)*}
}

pub trait LenType:
Send
+ Sync
+ Copy
+ Display
+ Debug
+ PartialEq
+ Add<Output = Self>
+ AddAssign
+ Sub<Output = Self>
+ SubAssign
+ PartialOrd
+ TryFrom<usize, Error: Debug>
+ TryInto<usize, Error: Debug>
{
const ZERO: Self;
const ONE: Self;
const MAX: usize;

fn from_usize(val: usize) -> Self {
val.try_into().unwrap()
}
fn into_usize(self) -> usize {
self.try_into().unwrap()
}
}

impl_lentype!(u8, u16, u32, usize);

macro_rules! impl_lentodefault {
($LenT:ty: $($len:literal),*) => {$(
impl LenToDefault for Const<$len> {
type Default = $LenT;
}
)*};
}

pub struct Const<const N: usize>;

#[diagnostic::on_unimplemented(
message = "Length `N` does not have a default LenType mapping",
note = "Provide the `LenType` explicitly, such as `usize`"
)]
pub trait LenToDefault {
type Default: LenType;
}

pub type DefaultLenType<const N: usize> = <Const<N> as LenToDefault>::Default;

impl_lentodefault!(u8: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255);
impl_lentodefault!(u16: 256, 300, 400, 500, 512, 600, 700, 800, 900, 1000, 1024, 2000, 2048, 4000, 4096, 8000, 8192, 16000, 16384, 32000, 32768, 65000, 65535);
impl_lentodefault!(u32: 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648);

pub const fn check_capacity_fits<LenT: LenType, const N: usize>() {
assert!(LenT::MAX >= N, "The capacity is larger than LenT can hold, increase the size of `LenT` or reduce the capacity")
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ pub mod deque;
pub mod histbuf;
mod indexmap;
mod indexset;
mod len_type;
pub mod linear_map;
mod slice;
pub mod storage;
Expand Down
4 changes: 2 additions & 2 deletions src/linear_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{

/// Base struct for [`LinearMap`] and [`LinearMapView`]
pub struct LinearMapInner<K, V, S: Storage> {
pub(crate) buffer: VecInner<(K, V), S>,
pub(crate) buffer: VecInner<(K, V), usize, S>,
}

/// A fixed capacity map/dictionary that performs lookups via linear search.
Expand Down Expand Up @@ -445,7 +445,7 @@ pub struct IntoIter<K, V, const N: usize>
where
K: Eq,
{
inner: <Vec<(K, V), N> as IntoIterator>::IntoIter,
inner: <Vec<(K, V), N, usize> as IntoIterator>::IntoIter,
}

impl<K, V, const N: usize> Iterator for IntoIter<K, V, N>
Expand Down
19 changes: 11 additions & 8 deletions src/string/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use core::{
};

use crate::{
len_type::LenType,
storage::{OwnedStorage, Storage, ViewStorage},
vec::VecInner,
Vec,
Expand Down Expand Up @@ -47,7 +48,7 @@ impl fmt::Display for FromUtf16Error {
/// In most cases you should use [`String`] or [`StringView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct StringInner<S: Storage> {
vec: VecInner<u8, S>,
vec: VecInner<u8, usize, S>,
}

/// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
Expand Down Expand Up @@ -210,9 +211,9 @@ impl<const N: usize> String<N> {
/// # Ok::<(), core::str::Utf8Error>(())
/// ```
#[inline]
pub fn from_utf8(vec: Vec<u8, N>) -> Result<Self, Utf8Error> {
pub fn from_utf8<LenT: LenType>(vec: Vec<u8, N, LenT>) -> Result<Self, Utf8Error> {
core::str::from_utf8(&vec)?;
Ok(Self { vec })
Ok(unsafe { Self::from_utf8_unchecked(vec) })
}

/// Convert UTF-8 bytes into a `String`, without checking that the string
Expand All @@ -237,8 +238,10 @@ impl<const N: usize> String<N> {
/// assert_eq!("💖", sparkle_heart);
/// ```
#[inline]
pub unsafe fn from_utf8_unchecked(vec: Vec<u8, N>) -> Self {
Self { vec }
pub unsafe fn from_utf8_unchecked<LenT: LenType>(vec: Vec<u8, N, LenT>) -> Self {
Self {
vec: vec.cast_len_type(),
}
}

/// Converts a `String` into a byte vector.
Expand All @@ -260,7 +263,7 @@ impl<const N: usize> String<N> {
/// # Ok::<(), ()>(())
/// ```
#[inline]
pub fn into_bytes(self) -> Vec<u8, N> {
pub fn into_bytes(self) -> Vec<u8, N, usize> {
self.vec
}

Expand Down Expand Up @@ -417,7 +420,7 @@ impl<S: Storage> StringInner<S> {
/// assert_eq!(s, "olleh");
/// # Ok::<(), ()>(())
/// ```
pub unsafe fn as_mut_vec(&mut self) -> &mut VecInner<u8, S> {
pub unsafe fn as_mut_vec(&mut self) -> &mut VecInner<u8, usize, S> {
&mut self.vec
}

Expand Down Expand Up @@ -1025,7 +1028,7 @@ mod tests {
#[test]
fn into_bytes() {
let s: String<4> = String::try_from("ab").unwrap();
let b: Vec<u8, 4> = s.into_bytes();
let b: Vec<u8, 4, usize> = s.into_bytes();
assert_eq!(b.len(), 2);
assert_eq!(&[b'a', b'b'], &b[..]);
}
Expand Down
46 changes: 23 additions & 23 deletions src/vec/drain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use core::{
slice,
};

use super::VecView;
use super::{LenType, VecView};

/// A draining iterator for [`Vec`](super::Vec).
///
Expand All @@ -19,25 +19,25 @@ use super::VecView;
/// use heapless::{vec, Vec};
///
/// let mut v = Vec::<_, 4>::from_array([0, 1, 2]);
/// let iter: vec::Drain<'_, _> = v.drain(..);
/// let iter: vec::Drain<'_, _, _> = v.drain(..);
/// ```
pub struct Drain<'a, T: 'a> {
pub struct Drain<'a, T: 'a, LenT: LenType> {
/// Index of tail to preserve
pub(super) tail_start: usize,
pub(super) tail_start: LenT,
/// Length of tail
pub(super) tail_len: usize,
pub(super) tail_len: LenT,
/// Current remaining range to remove
pub(super) iter: slice::Iter<'a, T>,
pub(super) vec: NonNull<VecView<T>>,
pub(super) vec: NonNull<VecView<T, LenT>>,
}

impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
impl<T: fmt::Debug, LenT: LenType> fmt::Debug for Drain<'_, T, LenT> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
}
}

impl<'a, T> Drain<'a, T> {
impl<'a, T, LenT: LenType> Drain<'a, T, LenT> {
/// Returns the remaining items of this iterator as a slice.
///
/// # Examples
Expand All @@ -57,16 +57,16 @@ impl<'a, T> Drain<'a, T> {
}
}

impl<'a, T> AsRef<[T]> for Drain<'a, T> {
impl<'a, T, LenT: LenType> AsRef<[T]> for Drain<'a, T, LenT> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}

unsafe impl<T: Sync> Sync for Drain<'_, T> {}
unsafe impl<T: Send> Send for Drain<'_, T> {}
unsafe impl<T: Sync, LenT: LenType> Sync for Drain<'_, T, LenT> {}
unsafe impl<T: Send, LenT: LenType> Send for Drain<'_, T, LenT> {}

impl<T> Iterator for Drain<'_, T> {
impl<T, LenT: LenType> Iterator for Drain<'_, T, LenT> {
type Item = T;

#[inline]
Expand All @@ -81,7 +81,7 @@ impl<T> Iterator for Drain<'_, T> {
}
}

impl<T> DoubleEndedIterator for Drain<'_, T> {
impl<T, LenT: LenType> DoubleEndedIterator for Drain<'_, T, LenT> {
#[inline]
fn next_back(&mut self) -> Option<T> {
self.iter
Expand All @@ -90,23 +90,23 @@ impl<T> DoubleEndedIterator for Drain<'_, T> {
}
}

impl<T> Drop for Drain<'_, T> {
impl<T, LenT: LenType> Drop for Drain<'_, T, LenT> {
fn drop(&mut self) {
/// Moves back the un-`Drain`ed elements to restore the original `Vec`.
struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>);
struct DropGuard<'r, 'a, T, LenT: LenType>(&'r mut Drain<'a, T, LenT>);

impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> {
impl<'r, 'a, T, LenT: LenType> Drop for DropGuard<'r, 'a, T, LenT> {
fn drop(&mut self) {
if self.0.tail_len > 0 {
if self.0.tail_len > LenT::ZERO {
unsafe {
let source_vec = self.0.vec.as_mut();
// memmove back untouched tail, update to new length
let start = source_vec.len();
let tail = self.0.tail_start;
if tail != start {
let dst = source_vec.as_mut_ptr().add(start);
let src = source_vec.as_ptr().add(tail);
ptr::copy(src, dst, self.0.tail_len);
let dst = source_vec.as_mut_ptr().add(start.into_usize());
let src = source_vec.as_ptr().add(tail.into_usize());
ptr::copy(src, dst, self.0.tail_len.into_usize());
}
source_vec.set_len(start + self.0.tail_len);
}
Expand All @@ -125,7 +125,7 @@ impl<T> Drop for Drain<'_, T> {
unsafe {
let vec = vec.as_mut();
let old_len = vec.len();
vec.set_len(old_len + drop_len + self.tail_len);
vec.set_len(old_len + LenT::from_usize(drop_len) + self.tail_len);
vec.truncate(old_len + self.tail_len);
}

Expand Down Expand Up @@ -159,9 +159,9 @@ impl<T> Drop for Drain<'_, T> {
}
}

impl<T> ExactSizeIterator for Drain<'_, T> {}
impl<T, LenT: LenType> ExactSizeIterator for Drain<'_, T, LenT> {}

impl<T> FusedIterator for Drain<'_, T> {}
impl<T, LenT: LenType> FusedIterator for Drain<'_, T, LenT> {}

#[cfg(test)]
mod tests {
Expand Down
Loading

0 comments on commit 7f97b86

Please sign in to comment.