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 d52af1e
Show file tree
Hide file tree
Showing 12 changed files with 381 additions and 202 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
11 changes: 6 additions & 5 deletions src/de.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
binary_heap::Kind as BinaryHeapKind, BinaryHeap, Deque, HistoryBuffer, IndexMap, IndexSet,
LinearMap, String, Vec,
LenType, LinearMap, String, Vec,
};
use core::{
fmt,
Expand Down Expand Up @@ -95,21 +95,22 @@ where
}
}

impl<'de, T, const N: usize> Deserialize<'de> for Vec<T, N>
impl<'de, T, LenT: LenType, const N: usize> Deserialize<'de> for Vec<T, N, LenT>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ValueVisitor<'de, T, const N: usize>(PhantomData<(&'de (), T)>);
struct ValueVisitor<'de, T, LenT: LenType, const N: usize>(PhantomData<(&'de (), T, LenT)>);

impl<'de, T, const N: usize> serde::de::Visitor<'de> for ValueVisitor<'de, T, N>
impl<'de, T, LenT, const N: usize> serde::de::Visitor<'de> for ValueVisitor<'de, T, LenT, N>
where
T: Deserialize<'de>,
LenT: LenType,
{
type Value = Vec<T, N>;
type Value = Vec<T, N, LenT>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence")
Expand Down
4 changes: 2 additions & 2 deletions src/defmt.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Defmt implementations for heapless types
use crate::{storage::Storage, string::StringInner, vec::VecInner};
use crate::{storage::Storage, string::StringInner, vec::VecInner, LenType};
use defmt::Formatter;

impl<T, S: Storage> defmt::Format for VecInner<T, S>
impl<T, LenT: LenType, S: Storage> defmt::Format for VecInner<T, LenT, S>
where
T: defmt::Format,
{
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
99 changes: 99 additions & 0 deletions src/len_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use core::{
fmt::{Debug, Display},
ops::{Add, AddAssign, Sub, SubAssign},
};

mod private {
pub trait Sealed {}

impl Sealed for u8 {}
impl Sealed for u16 {}
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
impl Sealed for u32 {}

impl Sealed for usize {}
}

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

/// A sealed trait representing a valid type to use as a length for a container.
///
/// This cannot be implemented in user code, and is restricted to `u8`, `u16`, `u32`, and `usize`.
pub trait LenType:
private::Sealed
+ Send
+ Sync
+ Copy
+ Display
+ Debug
+ PartialEq
+ Add<Output = Self>
+ AddAssign
+ Sub<Output = Self>
+ SubAssign
+ PartialOrd
+ TryFrom<usize, Error: Debug>
+ TryInto<usize, Error: Debug>
{
/// The zero value of the integer type.
const ZERO: Self;
/// The one value of the integer type.
const ONE: Self;
/// The maxiumum value of this type, as a usize.
const MAX: usize;

/// An infallible conversion from `usize` to `LenT`.
fn from_usize(val: usize) -> Self {
val.try_into().unwrap()
}

/// An infallible conversion from `LenT` to `usize`.
fn into_usize(self) -> usize {
self.try_into().unwrap()
}
}

impl_lentype!(
u8,
u16,
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
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")
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub use indexmap::{
ValuesMut as IndexMapValuesMut,
};
pub use indexset::{FnvIndexSet, IndexSet, Iter as IndexSetIter};
pub use len_type::LenType;
pub use linear_map::LinearMap;
pub use string::String;

Expand All @@ -107,6 +108,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
6 changes: 3 additions & 3 deletions src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
storage::Storage,
string::StringInner,
vec::VecInner,
IndexMap, IndexSet,
IndexMap, IndexSet, LenType,
};
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};

Expand Down Expand Up @@ -49,15 +49,15 @@ where
}
}

impl<T, St: Storage> Serialize for VecInner<T, St>
impl<T, LenT: LenType, St: Storage> Serialize for VecInner<T, LenT, St>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.len()))?;
let mut seq = serializer.serialize_seq(Some(self.len().into_usize()))?;
for element in self {
seq.serialize_element(element)?;
}
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
4 changes: 2 additions & 2 deletions src/ufmt.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{storage::Storage, string::StringInner, vec::VecInner};
use crate::{storage::Storage, string::StringInner, vec::VecInner, LenType};
use ufmt_write::uWrite;

impl<S: Storage> uWrite for StringInner<S> {
Expand All @@ -8,7 +8,7 @@ impl<S: Storage> uWrite for StringInner<S> {
}
}

impl<S: Storage> uWrite for VecInner<u8, S> {
impl<LenT: LenType, S: Storage> uWrite for VecInner<u8, LenT, S> {
type Error = ();
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.extend_from_slice(s.as_bytes())
Expand Down
Loading

0 comments on commit d52af1e

Please sign in to comment.