Repository: rust-embedded/heapless
Pull request #504: Implement a generic length parameter for Vec<T, N>
Author: login: GnomedDev
Created: 2024-07-18T20:11:10Z | Merged: 2025-04-10T17:47:43Z

Currently, `Vec<T, N>` always uses `usize` for the length field, which leads to silly situations like `Vec<u8, 4>` being `8` bytes large on 32 bit platforms. This PR introduces a generic to provide this length field as well as a default for many common length values to avoid much user code changing.

I am okay to revert sections of this PR if wanted, such as
- ~~The change of `usize` to `LenT` in many arguments and return types, if they are considered too breaking.~~ Done, `usize` is still used for indexing and as the `len` return type.
- Adding the length generic to `VecView`, this can be changed to only store `usize` at the cost of only `Vec<T, N, usize>` being able to unsize (or requiring a `Vec::cast_len_type` call before unsizing, at least).

This lays the ground work for followup PRs to implement a similar length generic on the other containers, but I'm starting with just `Vec` to test the waters.


Diff:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e4ad61ada..ceab01913d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 - Added `truncate` to `IndexMap`.
 - Added `get_index` and `get_index_mut` to `IndexMap`.
 - Added `String::uDisplay`.
+- Added `LenT` generic to `Vec<T, N>` and `VecView<T>` to save memory when using a sane capacity value.
 
 ### Changed
 
diff --git a/src/binary_heap.rs b/src/binary_heap.rs
index b15ec95913..31e2185fff 100644
--- a/src/binary_heap.rs
+++ b/src/binary_heap.rs
@@ -57,7 +57,7 @@ impl private::Sealed for Min {}
 /// struct if you want to write code that's generic over both.
 pub struct BinaryHeapInner<T, K, S: VecStorage<T> + ?Sized> {
     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.
@@ -181,7 +181,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
     }
 }
diff --git a/src/de.rs b/src/de.rs
index 455295b717..1c8c1c4825 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -1,6 +1,6 @@
 use crate::{
-    binary_heap::Kind as BinaryHeapKind, BinaryHeap, Deque, HistoryBuffer, IndexMap, IndexSet,
-    LinearMap, String, Vec,
+    binary_heap::Kind as BinaryHeapKind, len_type::LenType, BinaryHeap, Deque, HistoryBuffer,
+    IndexMap, IndexSet, LinearMap, String, Vec,
 };
 use core::{
     fmt,
@@ -95,7 +95,7 @@ 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>,
 {
@@ -103,13 +103,14 @@ where
     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")
diff --git a/src/defmt.rs b/src/defmt.rs
index 9c4d277940..9c8b0d5b9c 100644
--- a/src/defmt.rs
+++ b/src/defmt.rs
@@ -1,12 +1,13 @@
 //! Defmt implementations for heapless types
 
 use crate::{
+    len_type::LenType,
     string::{StringInner, StringStorage},
     vec::{VecInner, VecStorage},
 };
 use defmt::Formatter;
 
-impl<T, S: VecStorage<T> + ?Sized> defmt::Format for VecInner<T, S>
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> defmt::Format for VecInner<T, LenT, S>
 where
     T: defmt::Format,
 {
diff --git a/src/indexmap.rs b/src/indexmap.rs
index d3eb3fd4f6..ace113f35d 100644
--- a/src/indexmap.rs
+++ b/src/indexmap.rs
@@ -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],
 }
 
@@ -1417,7 +1417,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> {
diff --git a/src/len_type.rs b/src/len_type.rs
new file mode 100644
index 0000000000..370f9ef470
--- /dev/null
+++ b/src/len_type.rs
@@ -0,0 +1,107 @@
+use core::{
+    fmt::{Debug, Display},
+    ops::{Add, AddAssign, Sub, SubAssign},
+};
+
+pub trait 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 maximum value of this type, as a `usize`.
+    const MAX: usize;
+
+    /// An infallible conversion from `usize` to `LenT`.
+    #[inline]
+    fn from_usize(val: usize) -> Self {
+        val.try_into().unwrap()
+    }
+
+    /// An infallible conversion from `LenT` to `usize`.
+    #[inline]
+    fn into_usize(self) -> usize {
+        self.try_into().unwrap()
+    }
+}
+
+macro_rules! impl_lentype {
+    ($($(#[$meta:meta])* $LenT:ty),*) => {$(
+        $(#[$meta])*
+        impl Sealed for $LenT {
+            const ZERO: Self = 0;
+            const ONE: Self = 1;
+            const MAX: usize = Self::MAX as _;
+        }
+
+        $(#[$meta])*
+        impl LenType for $LenT {}
+    )*}
+}
+
+/// 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: Sealed {}
+
+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 SmallestLenType for Const<$len> {
+            type Type = $LenT;
+        }
+    )*};
+}
+
+/// A struct to create individual types for mapping with [`SmallestLenType`].
+///
+/// See the documentation of [`DefaultLenType`] for a detailed explanation.
+pub struct Const<const N: usize>;
+
+/// A trait to map [`Const`] to it's respective [`LenType`].
+///
+/// See the documentation of [`DefaultLenType`] for a detailed explanation.
+#[diagnostic::on_unimplemented(
+    message = "Length `N` does not have a default `LenType` mapping",
+    note = "Provide the `LenType` explicitly, such as `usize`"
+)]
+pub trait SmallestLenType {
+    type Type: LenType;
+}
+
+/// A type alias to perform the `const N: usize` -> `LenType` mapping.
+///
+/// This is impossible to perform directly, but it is possible to write a `const N: usize` -> related `Type` mapping via a const generic argument,
+/// then map from that to an unrelated type via a trait with associated types.
+///
+/// [`Const`] is the "related type" in the above explaination, [`SmallestLenType`] is the mapping trait.
+pub type DefaultLenType<const N: usize> = <Const<N> as SmallestLenType>::Type;
+
+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);
+#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
+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");
+}
diff --git a/src/lib.rs b/src/lib.rs
index cd6180a99e..0516c614e8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -165,6 +165,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;
 
@@ -178,6 +179,7 @@ pub mod deque;
 pub mod histbuf;
 mod indexmap;
 mod indexset;
+mod len_type;
 pub mod linear_map;
 mod slice;
 pub mod storage;
diff --git a/src/linear_map.rs b/src/linear_map.rs
index c96dece1ab..b7051737b2 100644
--- a/src/linear_map.rs
+++ b/src/linear_map.rs
@@ -89,7 +89,7 @@ pub type ViewStorage<K, V> = ViewVecStorage<(K, V)>;
 
 /// Base struct for [`LinearMap`] and [`LinearMapView`]
 pub struct LinearMapInner<K, V, S: LinearMapStorage<K, V> + ?Sized> {
-    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.
@@ -543,7 +543,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>
diff --git a/src/ser.rs b/src/ser.rs
index 26d2858e22..402cbfbfc6 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -4,6 +4,7 @@ use crate::{
     binary_heap::{BinaryHeapInner, Kind as BinaryHeapKind},
     deque::DequeInner,
     histbuf::{HistBufStorage, HistoryBufferInner},
+    len_type::LenType,
     linear_map::{LinearMapInner, LinearMapStorage},
     string::{StringInner, StringStorage},
     vec::{VecInner, VecStorage},
@@ -48,7 +49,7 @@ where
     }
 }
 
-impl<T, St: VecStorage<T> + ?Sized> Serialize for VecInner<T, St>
+impl<T, LenT: LenType, St: VecStorage<T>> Serialize for VecInner<T, LenT, St>
 where
     T: Serialize,
 {
diff --git a/src/string/mod.rs b/src/string/mod.rs
index 1a5b968a9a..29b885fee5 100644
--- a/src/string/mod.rs
+++ b/src/string/mod.rs
@@ -11,8 +11,11 @@ use core::{
     str::{self, Utf8Error},
 };
 
-use crate::vec::{OwnedVecStorage, Vec, VecInner, ViewVecStorage};
 use crate::CapacityError;
+use crate::{
+    len_type::LenType,
+    vec::{OwnedVecStorage, Vec, VecInner, ViewVecStorage},
+};
 
 mod drain;
 pub use drain::Drain;
@@ -131,7 +134,7 @@ pub type ViewStorage = ViewVecStorage<u8>;
 /// 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: StringStorage + ?Sized> {
-    vec: VecInner<u8, S>,
+    vec: VecInner<u8, usize, S>,
 }
 
 /// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
@@ -229,9 +232,11 @@ 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 })
+
+        // SAFETY: UTF-8 invariant has just been checked by `str::from_utf8`.
+        Ok(unsafe { Self::from_utf8_unchecked(vec) })
     }
 
     /// Convert UTF-8 bytes into a `String`, without checking that the string
@@ -256,8 +261,10 @@ impl<const N: usize> String<N> {
     /// assert_eq!("💖", sparkle_heart);
     /// ```
     #[inline]
-    pub const 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.
@@ -279,7 +286,7 @@ impl<const N: usize> String<N> {
     /// # Ok::<(), heapless::CapacityError>(())
     /// ```
     #[inline]
-    pub fn into_bytes(self) -> Vec<u8, N> {
+    pub fn into_bytes(self) -> Vec<u8, N, usize> {
         self.vec
     }
 }
@@ -457,7 +464,7 @@ impl<S: StringStorage + ?Sized> StringInner<S> {
     /// assert_eq!(s, "olleh");
     /// # Ok::<(), heapless::CapacityError>(())
     /// ```
-    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
     }
 
@@ -1068,7 +1075,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"ab", &b[..]);
     }
diff --git a/src/ufmt.rs b/src/ufmt.rs
index ef6e36ab7d..01e54165d8 100644
--- a/src/ufmt.rs
+++ b/src/ufmt.rs
@@ -1,4 +1,5 @@
 use crate::{
+    len_type::LenType,
     string::{StringInner, StringStorage},
     vec::{VecInner, VecStorage},
     CapacityError,
@@ -24,7 +25,7 @@ impl<S: StringStorage + ?Sized> uWrite for StringInner<S> {
     }
 }
 
-impl<S: VecStorage<u8> + ?Sized> uWrite for VecInner<u8, S> {
+impl<LenT: LenType, S: VecStorage<u8> + ?Sized> uWrite for VecInner<u8, LenT, S> {
     type Error = CapacityError;
     #[inline]
     fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
diff --git a/src/vec/drain.rs b/src/vec/drain.rs
index 5ba523fdfe..69af854e24 100644
--- a/src/vec/drain.rs
+++ b/src/vec/drain.rs
@@ -6,38 +6,31 @@ use core::{
     slice,
 };
 
+use crate::len_type::LenType;
+
 use super::VecView;
 
 /// A draining iterator for [`Vec`](super::Vec).
 ///
 /// This `struct` is created by [`Vec::drain`](super::Vec::drain).
 /// See its documentation for more.
-///
-/// # Example
-///
-/// ```
-/// use heapless::{vec, Vec};
-///
-/// let mut v = Vec::<_, 4>::from_array([0, 1, 2]);
-/// 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<T> Drain<'_, T> {
+impl<T, LenT: LenType> Drain<'_, T, LenT> {
     /// Returns the remaining items of this iterator as a slice.
     ///
     /// # Examples
@@ -57,16 +50,16 @@ impl<T> Drain<'_, T> {
     }
 }
 
-impl<T> AsRef<[T]> for Drain<'_, T> {
+impl<T, LenT: LenType> AsRef<[T]> for Drain<'_, 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]
@@ -81,7 +74,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
@@ -90,25 +83,26 @@ 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<T> Drop for DropGuard<'_, '_, T> {
+        impl<T, LenT: LenType> Drop for DropGuard<'_, '_, 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;
+                        let tail = self.0.tail_start.into_usize();
+                        let tail_len = self.0.tail_len.into_usize();
                         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);
+                            ptr::copy(src, dst, tail_len);
                         }
-                        source_vec.set_len(start + self.0.tail_len);
+                        source_vec.set_len(start + tail_len);
                     }
                 }
             }
@@ -125,8 +119,9 @@ 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.truncate(old_len + self.tail_len);
+                let tail_len = self.tail_len.into_usize();
+                vec.set_len(old_len + drop_len + tail_len);
+                vec.truncate(old_len + tail_len);
             }
 
             return;
@@ -159,9 +154,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 {
diff --git a/src/vec/mod.rs b/src/vec/mod.rs
index ec8e6ccbeb..b8039c94aa 100644
--- a/src/vec/mod.rs
+++ b/src/vec/mod.rs
@@ -11,6 +11,7 @@ use core::{
     slice,
 };
 
+use crate::len_type::{check_capacity_fits, DefaultLenType, LenType};
 use crate::CapacityError;
 
 mod drain;
@@ -21,6 +22,7 @@ mod storage {
     use crate::{
         binary_heap::{BinaryHeapInner, BinaryHeapView},
         deque::{DequeInner, DequeView},
+        len_type::LenType,
     };
 
     use super::{VecInner, VecView};
@@ -56,10 +58,12 @@ mod storage {
         fn borrow(&self) -> &[MaybeUninit<T>];
         fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>];
 
-        fn as_vec_view(this: &VecInner<T, Self>) -> &VecView<T>
+        fn as_vec_view<LenT: LenType>(this: &VecInner<T, LenT, Self>) -> &VecView<T, LenT>
         where
             Self: VecStorage<T>;
-        fn as_vec_mut_view(this: &mut VecInner<T, Self>) -> &mut VecView<T>
+        fn as_vec_mut_view<LenT: LenType>(
+            this: &mut VecInner<T, LenT, Self>,
+        ) -> &mut VecView<T, LenT>
         where
             Self: VecStorage<T>;
 
@@ -98,13 +102,15 @@ mod storage {
             &mut self.buffer
         }
 
-        fn as_vec_view(this: &VecInner<T, Self>) -> &VecView<T>
+        fn as_vec_view<LenT: LenType>(this: &VecInner<T, LenT, Self>) -> &VecView<T, LenT>
         where
             Self: VecStorage<T>,
         {
             this
         }
-        fn as_vec_mut_view(this: &mut VecInner<T, Self>) -> &mut VecView<T>
+        fn as_vec_mut_view<LenT: LenType>(
+            this: &mut VecInner<T, LenT, Self>,
+        ) -> &mut VecView<T, LenT>
         where
             Self: VecStorage<T>,
         {
@@ -148,13 +154,15 @@ mod storage {
             &mut self.buffer
         }
 
-        fn as_vec_view(this: &VecInner<T, Self>) -> &VecView<T>
+        fn as_vec_view<LenT: LenType>(this: &VecInner<T, LenT, Self>) -> &VecView<T, LenT>
         where
             Self: VecStorage<T>,
         {
             this
         }
-        fn as_vec_mut_view(this: &mut VecInner<T, Self>) -> &mut VecView<T>
+        fn as_vec_mut_view<LenT: LenType>(
+            this: &mut VecInner<T, LenT, Self>,
+        ) -> &mut VecView<T, LenT>
         where
             Self: VecStorage<T>,
         {
@@ -200,9 +208,9 @@ pub use drain::Drain;
 ///
 /// In most cases you should use [`Vec`] or [`VecView`] directly. Only use this
 /// struct if you want to write code that's generic over both.
-pub struct VecInner<T, S: VecStorage<T> + ?Sized> {
+pub struct VecInner<T, LenT: LenType, S: VecStorage<T> + ?Sized> {
     phantom: PhantomData<T>,
-    len: usize,
+    len: LenT,
     buffer: S,
 }
 
@@ -241,9 +249,14 @@ pub struct VecInner<T, S: VecStorage<T> + ?Sized> {
 /// use heapless::{Vec, VecView};
 ///
 /// let vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
-/// let view: &VecView<_> = &vec;
+/// let view: &VecView<_, _> = &vec;
 /// ```
-pub type Vec<T, const N: usize> = VecInner<T, OwnedVecStorage<T, N>>;
+///
+/// For uncommmon capacity values, or in generic scenarios, you may have to provide the `LenT` generic yourself.
+///
+/// This should be the smallest unsigned integer type that your capacity fits in, or `usize` if you don't want to consider this.
+pub type Vec<T, const N: usize, LenT = DefaultLenType<N>> =
+    VecInner<T, LenT, OwnedVecStorage<T, N>>;
 
 /// A [`Vec`] with dynamic capacity
 ///
@@ -259,16 +272,16 @@ pub type Vec<T, const N: usize> = VecInner<T, OwnedVecStorage<T, N>>;
 /// use heapless::{Vec, VecView};
 ///
 /// let mut vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
-/// let view: &VecView<_> = &vec;
+/// let view: &VecView<_, _> = &vec;
 /// assert_eq!(view, &[1, 2, 3, 4]);
 ///
-/// let mut_view: &mut VecView<_> = &mut vec;
+/// let mut_view: &mut VecView<_, _> = &mut vec;
 /// mut_view.push(5);
 /// assert_eq!(vec, [1, 2, 3, 4, 5]);
 /// ```
-pub type VecView<T> = VecInner<T, ViewVecStorage<T>>;
+pub type VecView<T, LenT = usize> = VecInner<T, LenT, ViewVecStorage<T>>;
 
-impl<T, const N: usize> Vec<T, N> {
+impl<T, LenT: LenType, const N: usize> Vec<T, N, LenT> {
     const ELEM: MaybeUninit<T> = MaybeUninit::uninit();
     const INIT: [MaybeUninit<T>; N] = [Self::ELEM; N]; // important for optimization of `new`
 
@@ -286,9 +299,11 @@ impl<T, const N: usize> Vec<T, N> {
     /// static mut X: Vec<u8, 16> = Vec::new();
     /// ```
     pub const fn new() -> Self {
+        const { check_capacity_fits::<LenT, N>() }
+
         Self {
             phantom: PhantomData,
-            len: 0,
+            len: LenT::ZERO,
             buffer: VecStorageInner { buffer: Self::INIT },
         }
     }
@@ -333,7 +348,7 @@ impl<T, const N: usize> Vec<T, N> {
         if N == M {
             Self {
                 phantom: PhantomData,
-                len: N,
+                len: LenT::from_usize(N),
                 // NOTE(unsafe) ManuallyDrop<[T; M]> and [MaybeUninit<T>; N]
                 // have the same layout when N == M.
                 buffer: unsafe { mem::transmute_copy(&src) },
@@ -347,7 +362,7 @@ impl<T, const N: usize> Vec<T, N> {
                 dst_elem.write(unsafe { ptr::read(src_elem) });
             }
 
-            v.len = M;
+            unsafe { v.set_len(M) };
             v
         }
     }
@@ -392,9 +407,27 @@ impl<T, const N: usize> Vec<T, N> {
         }
         new
     }
+
+    /// Casts the `LenT` type to a new type, preserving everything else about the vector.
+    ///
+    /// This can be useful if you need to pass a `Vec<T, N, u8>` into a `Vec<T, N, usize>` for example.
+    ///
+    /// This will check at compile time if the `N` value will fit into `NewLenT`, and error if not.
+    pub fn cast_len_type<NewLenT: LenType>(self) -> Vec<T, N, NewLenT> {
+        const { check_capacity_fits::<NewLenT, N>() }
+        let this = ManuallyDrop::new(self);
+
+        // SAFETY: Pointer argument is derived from a reference, meeting the safety documented invariants.
+        // This also prevents double drops by wrapping `self` in `ManuallyDrop`.
+        Vec {
+            len: NewLenT::from_usize(this.len()),
+            buffer: unsafe { ptr::read(&this.buffer) },
+            phantom: PhantomData,
+        }
+    }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> VecInner<T, LenT, 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.
@@ -427,7 +460,7 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     /// v.drain(..);
     /// assert_eq!(v, &[]);
     /// ```
-    pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
+    pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, LenT>
     where
         R: RangeBounds<usize>,
     {
@@ -450,8 +483,8 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
             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,
-                tail_len: len - end,
+                tail_start: LenT::from_usize(end),
+                tail_len: LenT::from_usize(len - end),
                 iter: range_slice.iter(),
                 vec,
             }
@@ -464,7 +497,7 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     /// ```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();
+    /// 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>>`:
@@ -472,10 +505,10 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     /// ```rust
     /// # use heapless::{Vec, VecView};
     /// let vec: Vec<u8, 10> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
-    /// let view: &VecView<u8> = &vec;
+    /// let view: &VecView<u8, _> = &vec;
     /// ```
     #[inline]
-    pub fn as_view(&self) -> &VecView<T> {
+    pub fn as_view(&self) -> &VecView<T, LenT> {
         S::as_vec_view(self)
     }
 
@@ -483,19 +516,19 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     ///
     /// ```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();
+    /// let mut vec: Vec<u8, 10, u8> = 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;
+    /// let mut vec: Vec<u8, 10, u8> = 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> {
+    pub fn as_mut_view(&mut self) -> &mut VecView<T, LenT> {
         S::as_vec_mut_view(self)
     }
 
@@ -523,7 +556,12 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     pub fn as_slice(&self) -> &[T] {
         // NOTE(unsafe) avoid bound checks in the slicing operation
         // &buffer[..self.len]
-        unsafe { slice::from_raw_parts(self.buffer.borrow().as_ptr().cast::<T>(), self.len) }
+        unsafe {
+            slice::from_raw_parts(
+                self.buffer.borrow().as_ptr().cast::<T>(),
+                self.len.into_usize(),
+            )
+        }
     }
 
     /// Extracts a mutable slice containing the entire vector.
@@ -543,7 +581,10 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
         // NOTE(unsafe) avoid bound checks in the slicing operation
         // &mut buffer[..self.len]
         unsafe {
-            slice::from_raw_parts_mut(self.buffer.borrow_mut().as_mut_ptr().cast::<T>(), self.len)
+            slice::from_raw_parts_mut(
+                self.buffer.borrow_mut().as_mut_ptr().cast::<T>(),
+                self.len.into_usize(),
+            )
         }
     }
 
@@ -590,21 +631,23 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     where
         T: Clone,
     {
-        pub fn extend_from_slice_inner<T>(
-            len: &mut usize,
+        pub fn extend_from_slice_inner<T, LenT: LenType>(
+            len: &mut LenT,
             buf: &mut [MaybeUninit<T>],
             other: &[T],
         ) -> Result<(), CapacityError>
         where
             T: Clone,
         {
-            if *len + other.len() > buf.len() {
+            if len.into_usize() + other.len() > buf.len() {
                 // won't fit in the `Vec`; don't modify anything and return an error
                 Err(CapacityError)
             } else {
                 for elem in other {
-                    unsafe { *buf.get_unchecked_mut(*len) = MaybeUninit::new(elem.clone()) }
-                    *len += 1;
+                    unsafe {
+                        *buf.get_unchecked_mut(len.into_usize()) = MaybeUninit::new(elem.clone());
+                    }
+                    *len += LenT::ONE;
                 }
                 Ok(())
             }
@@ -615,10 +658,10 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
 
     /// Removes the last element from a vector and returns it, or `None` if it's empty
     pub fn pop(&mut self) -> Option<T> {
-        if self.len != 0 {
-            Some(unsafe { self.pop_unchecked() })
-        } else {
+        if self.len == LenT::ZERO {
             None
+        } else {
+            Some(unsafe { self.pop_unchecked() })
         }
     }
 
@@ -626,7 +669,7 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     ///
     /// Returns back the `item` if the vector is full.
     pub fn push(&mut self, item: T) -> Result<(), T> {
-        if self.len < self.capacity() {
+        if self.len() < self.capacity() {
             unsafe { self.push_unchecked(item) }
             Ok(())
         } else {
@@ -642,10 +685,10 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     pub unsafe fn pop_unchecked(&mut self) -> T {
         debug_assert!(!self.is_empty());
 
-        self.len -= 1;
+        self.len -= LenT::ONE;
         self.buffer
             .borrow_mut()
-            .get_unchecked_mut(self.len)
+            .get_unchecked_mut(self.len.into_usize())
             .as_ptr()
             .read()
     }
@@ -660,9 +703,12 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
         // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
         debug_assert!(!self.is_full());
 
-        *self.buffer.borrow_mut().get_unchecked_mut(self.len) = MaybeUninit::new(item);
+        *self
+            .buffer
+            .borrow_mut()
+            .get_unchecked_mut(self.len.into_usize()) = MaybeUninit::new(item);
 
-        self.len += 1;
+        self.len += LenT::ONE;
     }
 
     /// Shortens the vector, keeping the first `len` elements and dropping the rest.
@@ -678,12 +724,12 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
             // Note: It's intentional that this is `>` and not `>=`.
             //       Changing it to `>=` has negative performance
             //       implications in some cases. See rust-lang/rust#78884 for more.
-            if len > self.len {
+            if len > self.len() {
                 return;
             }
-            let remaining_len = self.len - len;
+            let remaining_len = self.len() - len;
             let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len);
-            self.len = len;
+            self.len = LenT::from_usize(len);
             ptr::drop_in_place(s);
         }
     }
@@ -703,8 +749,8 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
             return Err(CapacityError);
         }
 
-        if new_len > self.len {
-            while self.len < new_len {
+        if new_len > self.len() {
+            while self.len() < new_len {
                 self.push(value.clone()).ok();
             }
         } else {
@@ -820,7 +866,7 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     pub unsafe fn set_len(&mut self, new_len: usize) {
         debug_assert!(new_len <= self.capacity());
 
-        self.len = new_len;
+        self.len = LenT::from_usize(new_len);
     }
 
     /// Removes an element from the vector and returns it.
@@ -851,7 +897,7 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     /// assert_eq!(&*v, ["baz", "qux"]);
     /// ```
     pub fn swap_remove(&mut self, index: usize) -> T {
-        assert!(index < self.len);
+        assert!(index < self.len());
         unsafe { self.swap_remove_unchecked(index) }
     }
 
@@ -888,18 +934,18 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
         let value = ptr::read(self.as_ptr().add(index));
         let base_ptr = self.as_mut_ptr();
         ptr::copy(base_ptr.add(length - 1), base_ptr.add(index), 1);
-        self.len -= 1;
+        self.len -= LenT::ONE;
         value
     }
 
     /// Returns true if the vec is full
     pub fn is_full(&self) -> bool {
-        self.len == self.capacity()
+        self.len() == self.capacity()
     }
 
     /// Returns true if the vec is empty
     pub fn is_empty(&self) -> bool {
-        self.len == 0
+        self.len == LenT::ZERO
     }
 
     /// Returns `true` if `needle` is a prefix of the Vec.
@@ -921,7 +967,7 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
         T: PartialEq,
     {
         let n = needle.len();
-        self.len >= n && needle == &self[..n]
+        self.len() >= n && needle == &self[..n]
     }
 
     /// Returns `true` if `needle` is a suffix of the Vec.
@@ -1107,7 +1153,7 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     where
         F: FnMut(&mut T) -> bool,
     {
-        let original_len = self.len();
+        let original_len = self.len;
         // Avoid double drop if the drop guard is not executed,
         // since we may make some holes during the process.
         unsafe { self.set_len(0) };
@@ -1123,56 +1169,57 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
         // This drop guard will be invoked when predicate or `drop` of element panicked.
         // It shifts unchecked elements to cover holes and `set_len` to the correct length.
         // In cases when predicate and `drop` never panick, it will be optimized out.
-        struct BackshiftOnDrop<'a, T, S: VecStorage<T> + ?Sized> {
-            v: &'a mut VecInner<T, S>,
-            processed_len: usize,
-            deleted_cnt: usize,
-            original_len: usize,
+        struct BackshiftOnDrop<'a, T, LenT: LenType, S: VecStorage<T> + ?Sized> {
+            v: &'a mut VecInner<T, LenT, S>,
+            processed_len: LenT,
+            deleted_cnt: LenT,
+            original_len: LenT,
         }
 
-        impl<T, S: VecStorage<T> + ?Sized> Drop for BackshiftOnDrop<'_, T, S> {
+        impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> Drop for BackshiftOnDrop<'_, T, LenT, S> {
             fn drop(&mut self) {
-                if self.deleted_cnt > 0 {
+                if self.deleted_cnt > LenT::ZERO {
                     // SAFETY: Trailing unchecked items must be valid since we never touch them.
                     unsafe {
                         ptr::copy(
-                            self.v.as_ptr().add(self.processed_len),
+                            self.v.as_ptr().add(self.processed_len.into_usize()),
                             self.v
                                 .as_mut_ptr()
-                                .add(self.processed_len - self.deleted_cnt),
-                            self.original_len - self.processed_len,
+                                .add((self.processed_len - self.deleted_cnt).into_usize()),
+                            (self.original_len - self.processed_len).into_usize(),
                         );
                     }
                 }
                 // SAFETY: After filling holes, all items are in contiguous memory.
                 unsafe {
-                    self.v.set_len(self.original_len - self.deleted_cnt);
+                    self.v
+                        .set_len((self.original_len - self.deleted_cnt).into_usize());
                 }
             }
         }
 
         let mut g = BackshiftOnDrop {
             v: self,
-            processed_len: 0,
-            deleted_cnt: 0,
+            processed_len: LenT::ZERO,
+            deleted_cnt: LenT::ZERO,
             original_len,
         };
 
-        fn process_loop<F, T, S: VecStorage<T> + ?Sized, const DELETED: bool>(
-            original_len: usize,
+        fn process_loop<F, T, LenT: LenType, S: VecStorage<T> + ?Sized, const DELETED: bool>(
+            original_len: LenT,
             f: &mut F,
-            g: &mut BackshiftOnDrop<'_, T, S>,
+            g: &mut BackshiftOnDrop<'_, T, LenT, S>,
         ) where
             F: FnMut(&mut T) -> bool,
         {
             while g.processed_len != original_len {
                 let p = g.v.as_mut_ptr();
                 // SAFETY: Unchecked element must be valid.
-                let cur = unsafe { &mut *p.add(g.processed_len) };
+                let cur = unsafe { &mut *p.add(g.processed_len.into_usize()) };
                 if !f(cur) {
                     // Advance early to avoid double drop if `drop_in_place` panicked.
-                    g.processed_len += 1;
-                    g.deleted_cnt += 1;
+                    g.processed_len += LenT::ONE;
+                    g.deleted_cnt += LenT::ONE;
                     // SAFETY: We never touch this element again after dropped.
                     unsafe { ptr::drop_in_place(cur) };
                     // We already advanced the counter.
@@ -1186,19 +1233,19 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
                     // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element.
                     // We use copy for move, and never touch this element again.
                     unsafe {
-                        let hole_slot = p.add(g.processed_len - g.deleted_cnt);
+                        let hole_slot = p.add((g.processed_len - g.deleted_cnt).into_usize());
                         ptr::copy_nonoverlapping(cur, hole_slot, 1);
                     }
                 }
-                g.processed_len += 1;
+                g.processed_len += LenT::ONE;
             }
         }
 
         // Stage 1: Nothing was deleted.
-        process_loop::<F, T, S, false>(original_len, &mut f, &mut g);
+        process_loop::<F, T, LenT, S, false>(original_len, &mut f, &mut g);
 
         // Stage 2: Some elements were deleted.
-        process_loop::<F, T, S, true>(original_len, &mut f, &mut g);
+        process_loop::<F, T, LenT, S, true>(original_len, &mut f, &mut g);
 
         // All item are processed. This can be optimized to `set_len` by LLVM.
         drop(g);
@@ -1232,19 +1279,19 @@ impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
     /// ```
     #[inline]
     pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
-        &mut self.buffer.borrow_mut()[self.len..]
+        &mut self.buffer.borrow_mut()[self.len.into_usize()..]
     }
 }
 
 // Trait implementations
 
-impl<T, const N: usize> Default for Vec<T, N> {
+impl<T, LenT: LenType, const N: usize> Default for Vec<T, N, LenT> {
     fn default() -> Self {
         Self::new()
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> fmt::Debug for VecInner<T, S>
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> fmt::Debug for VecInner<T, LenT, S>
 where
     T: fmt::Debug,
 {
@@ -1253,7 +1300,7 @@ where
     }
 }
 
-impl<S: VecStorage<u8> + ?Sized> fmt::Write for VecInner<u8, S> {
+impl<LenT: LenType, S: VecStorage<u8> + ?Sized> fmt::Write for VecInner<u8, LenT, S> {
     fn write_str(&mut self, s: &str) -> fmt::Result {
         match self.extend_from_slice(s.as_bytes()) {
             Ok(()) => Ok(()),
@@ -1262,13 +1309,13 @@ impl<S: VecStorage<u8> + ?Sized> fmt::Write for VecInner<u8, S> {
     }
 }
 
-impl<T, const N: usize, const M: usize> From<[T; M]> for Vec<T, N> {
+impl<T, LenT: LenType, const N: usize, const M: usize> From<[T; M]> for Vec<T, N, LenT> {
     fn from(array: [T; M]) -> Self {
         Self::from_array(array)
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> Drop for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> Drop for VecInner<T, LenT, S> {
     fn drop(&mut self) {
         let mut_slice = self.as_mut_slice();
         // We drop each element used in the vector by turning into a `&mut [T]`.
@@ -1279,7 +1326,7 @@ impl<T, S: VecStorage<T> + ?Sized> Drop for VecInner<T, S> {
 
 #[cfg(feature = "alloc")]
 /// Converts the given `alloc::vec::Vec<T>` into a `Vec<T, N>`.
-impl<T, const N: usize> TryFrom<alloc::vec::Vec<T>> for Vec<T, N> {
+impl<T, LenT: LenType, const N: usize> TryFrom<alloc::vec::Vec<T>> for Vec<T, N, LenT> {
     type Error = CapacityError;
 
     /// Converts the given `alloc::vec::Vec<T>` into a `Vec<T, N>`.
@@ -1288,7 +1335,7 @@ impl<T, const N: usize> TryFrom<alloc::vec::Vec<T>> for Vec<T, N> {
     ///
     /// Returns `Err` if the length of the `alloc::vec::Vec<T>` is greater than `N`.
     fn try_from(alloc_vec: alloc::vec::Vec<T>) -> Result<Self, Self::Error> {
-        let mut vec = Vec::new();
+        let mut vec = Self::new();
 
         for e in alloc_vec {
             // Push each element individually to allow handling capacity errors.
@@ -1301,7 +1348,7 @@ impl<T, const N: usize> TryFrom<alloc::vec::Vec<T>> for Vec<T, N> {
 
 #[cfg(feature = "alloc")]
 /// Converts the given `Vec<T, N>` into an `alloc::vec::Vec<T>`.
-impl<T, const N: usize> TryFrom<Vec<T, N>> for alloc::vec::Vec<T> {
+impl<T, LenT: LenType, const N: usize> TryFrom<Vec<T, N, LenT>> for alloc::vec::Vec<T> {
     type Error = alloc::collections::TryReserveError;
 
     /// Converts the given `Vec<T, N>` into an `alloc::vec::Vec<T>`.
@@ -1309,8 +1356,8 @@ impl<T, const N: usize> TryFrom<Vec<T, N>> for alloc::vec::Vec<T> {
     /// # Errors
     ///
     /// Returns `Err` if the `alloc::vec::Vec` fails to allocate memory.
-    fn try_from(vec: Vec<T, N>) -> Result<Self, Self::Error> {
-        let mut alloc_vec = alloc::vec::Vec::new();
+    fn try_from(vec: Vec<T, N, LenT>) -> Result<Self, Self::Error> {
+        let mut alloc_vec = Self::new();
 
         // Allocate enough space for the elements, return an error if the
         // allocation fails.
@@ -1324,7 +1371,7 @@ impl<T, const N: usize> TryFrom<Vec<T, N>> for alloc::vec::Vec<T> {
     }
 }
 
-impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec<T, N> {
+impl<'a, T: Clone, LenT: LenType, const N: usize> TryFrom<&'a [T]> for Vec<T, N, LenT> {
     type Error = CapacityError;
 
     fn try_from(slice: &'a [T]) -> Result<Self, Self::Error> {
@@ -1332,7 +1379,7 @@ impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec<T, N> {
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> Extend<T> for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> Extend<T> for VecInner<T, LenT, S> {
     fn extend<I>(&mut self, iter: I)
     where
         I: IntoIterator<Item = T>,
@@ -1341,7 +1388,7 @@ impl<T, S: VecStorage<T> + ?Sized> Extend<T> for VecInner<T, S> {
     }
 }
 
-impl<'a, T, S: VecStorage<T> + ?Sized> Extend<&'a T> for VecInner<T, S>
+impl<'a, T, LenT: LenType, S: VecStorage<T> + ?Sized> Extend<&'a T> for VecInner<T, LenT, S>
 where
     T: 'a + Copy,
 {
@@ -1353,7 +1400,7 @@ where
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> hash::Hash for VecInner<T, S>
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> hash::Hash for VecInner<T, LenT, S>
 where
     T: core::hash::Hash,
 {
@@ -1362,7 +1409,7 @@ where
     }
 }
 
-impl<'a, T, S: VecStorage<T> + ?Sized> IntoIterator for &'a VecInner<T, S> {
+impl<'a, T, LenT: LenType, S: VecStorage<T> + ?Sized> IntoIterator for &'a VecInner<T, LenT, S> {
     type Item = &'a T;
     type IntoIter = slice::Iter<'a, T>;
 
@@ -1371,7 +1418,9 @@ impl<'a, T, S: VecStorage<T> + ?Sized> IntoIterator for &'a VecInner<T, S> {
     }
 }
 
-impl<'a, T, S: VecStorage<T> + ?Sized> IntoIterator for &'a mut VecInner<T, S> {
+impl<'a, T, LenT: LenType, S: VecStorage<T> + ?Sized> IntoIterator
+    for &'a mut VecInner<T, LenT, S>
+{
     type Item = &'a mut T;
     type IntoIter = slice::IterMut<'a, T>;
 
@@ -1380,7 +1429,7 @@ impl<'a, T, S: VecStorage<T> + ?Sized> IntoIterator for &'a mut VecInner<T, S> {
     }
 }
 
-impl<T, const N: usize> FromIterator<T> for Vec<T, N> {
+impl<T, LenT: LenType, const N: usize> FromIterator<T> for Vec<T, N, LenT> {
     fn from_iter<I>(iter: I) -> Self
     where
         I: IntoIterator<Item = T>,
@@ -1396,24 +1445,24 @@ impl<T, const N: usize> FromIterator<T> for Vec<T, N> {
 /// An iterator that moves out of an [`Vec`][`Vec`].
 ///
 /// This struct is created by calling the `into_iter` method on [`Vec`][`Vec`].
-pub struct IntoIter<T, const N: usize> {
-    vec: Vec<T, N>,
-    next: usize,
+pub struct IntoIter<T, const N: usize, LenT: LenType> {
+    vec: Vec<T, N, LenT>,
+    next: LenT,
 }
 
-impl<T, const N: usize> Iterator for IntoIter<T, N> {
+impl<T, LenT: LenType, const N: usize> Iterator for IntoIter<T, N, LenT> {
     type Item = T;
     fn next(&mut self) -> Option<Self::Item> {
-        if self.next < self.vec.len() {
+        if self.next < self.vec.len {
             let item = unsafe {
                 self.vec
                     .buffer
                     .buffer
-                    .get_unchecked_mut(self.next)
+                    .get_unchecked_mut(self.next.into_usize())
                     .as_ptr()
                     .read()
             };
-            self.next += 1;
+            self.next += LenT::ONE;
             Some(item)
         } else {
             None
@@ -1421,105 +1470,128 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
     }
 }
 
-impl<T, const N: usize> Clone for IntoIter<T, N>
+impl<T, LenT: LenType, const N: usize> Clone for IntoIter<T, N, LenT>
 where
     T: Clone,
 {
     fn clone(&self) -> Self {
         let mut vec = Vec::new();
 
-        if self.next < self.vec.len() {
+        if self.next < self.vec.len {
             let s = unsafe {
                 slice::from_raw_parts(
-                    self.vec.buffer.buffer.as_ptr().cast::<T>().add(self.next),
-                    self.vec.len() - self.next,
+                    self.vec
+                        .buffer
+                        .buffer
+                        .as_ptr()
+                        .cast::<T>()
+                        .add(self.next.into_usize()),
+                    (self.vec.len - self.next).into_usize(),
                 )
             };
             vec.extend_from_slice(s).ok();
         }
 
-        Self { vec, next: 0 }
+        Self {
+            vec,
+            next: LenT::ZERO,
+        }
     }
 }
 
-impl<T, const N: usize> Drop for IntoIter<T, N> {
+impl<T, LenT: LenType, const N: usize> Drop for IntoIter<T, N, LenT> {
     fn drop(&mut self) {
         unsafe {
             // Drop all the elements that have not been moved out of vec
-            ptr::drop_in_place(&mut self.vec.as_mut_slice()[self.next..]);
+            ptr::drop_in_place(&mut self.vec.as_mut_slice()[self.next.into_usize()..]);
             // Prevent dropping of other elements
-            self.vec.len = 0;
+            self.vec.len = LenT::ZERO;
         }
     }
 }
 
-impl<T, const N: usize> IntoIterator for Vec<T, N> {
+impl<T, LenT: LenType, const N: usize> IntoIterator for Vec<T, N, LenT> {
     type Item = T;
-    type IntoIter = IntoIter<T, N>;
+    type IntoIter = IntoIter<T, N, LenT>;
 
     fn into_iter(self) -> Self::IntoIter {
-        IntoIter { vec: self, next: 0 }
+        IntoIter {
+            vec: self,
+            next: LenT::ZERO,
+        }
     }
 }
 
-impl<A, B, SA: VecStorage<A> + ?Sized, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>>
-    for VecInner<A, SA>
+impl<A, B, LenTA, LenTB, SA, SB> PartialEq<VecInner<B, LenTB, SB>> for VecInner<A, LenTA, SA>
 where
     A: PartialEq<B>,
+    LenTA: LenType,
+    LenTB: LenType,
+    SA: VecStorage<A> + ?Sized,
+    SB: VecStorage<B> + ?Sized,
 {
-    fn eq(&self, other: &VecInner<B, SB>) -> bool {
+    fn eq(&self, other: &VecInner<B, LenTB, SB>) -> bool {
         self.as_slice().eq(other.as_slice())
     }
 }
 
-impl<A, B, const M: usize, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>> for [A; M]
+impl<A, B, LenTB, const M: usize, SB> PartialEq<VecInner<B, LenTB, SB>> for [A; M]
 where
     A: PartialEq<B>,
+    LenTB: LenType,
+    SB: VecStorage<B>,
 {
-    fn eq(&self, other: &VecInner<B, SB>) -> bool {
+    fn eq(&self, other: &VecInner<B, LenTB, SB>) -> bool {
         self.eq(other.as_slice())
     }
 }
 
-impl<A, B, SB: VecStorage<B> + ?Sized, const M: usize> PartialEq<VecInner<B, SB>> for &[A; M]
+impl<A, B, LenTB, SB, const M: usize> PartialEq<VecInner<B, LenTB, SB>> for &[A; M]
 where
     A: PartialEq<B>,
+    LenTB: LenType,
+    SB: VecStorage<B>,
 {
-    fn eq(&self, other: &VecInner<B, SB>) -> bool {
+    fn eq(&self, other: &VecInner<B, LenTB, SB>) -> bool {
         (*self).eq(other)
     }
 }
 
-impl<A, B, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>> for [A]
+impl<A, B, LenTB, SB> PartialEq<VecInner<B, LenTB, SB>> for [A]
 where
     A: PartialEq<B>,
+    LenTB: LenType,
+    SB: VecStorage<B>,
 {
-    fn eq(&self, other: &VecInner<B, SB>) -> bool {
+    fn eq(&self, other: &VecInner<B, LenTB, SB>) -> bool {
         self.eq(other.as_slice())
     }
 }
 
-impl<A, B, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>> for &[A]
+impl<A, B, LenTB, SB> PartialEq<VecInner<B, LenTB, SB>> for &[A]
 where
     A: PartialEq<B>,
+    LenTB: LenType,
+    SB: VecStorage<B>,
 {
-    fn eq(&self, other: &VecInner<B, SB>) -> bool {
+    fn eq(&self, other: &VecInner<B, LenTB, SB>) -> bool {
         (*self).eq(other)
     }
 }
 
-impl<A, B, SB: VecStorage<B> + ?Sized> PartialEq<VecInner<B, SB>> for &mut [A]
+impl<A, B, LenTB: LenType, SB: VecStorage<B>> PartialEq<VecInner<B, LenTB, SB>> for &mut [A]
 where
     A: PartialEq<B>,
 {
-    fn eq(&self, other: &VecInner<B, SB>) -> bool {
+    fn eq(&self, other: &VecInner<B, LenTB, SB>) -> bool {
         (**self).eq(other)
     }
 }
 
-impl<A, B, SA: VecStorage<A> + ?Sized, const N: usize> PartialEq<[B; N]> for VecInner<A, SA>
+impl<A, B, LenTA: LenType, SA, const N: usize> PartialEq<[B; N]> for VecInner<A, LenTA, SA>
 where
     A: PartialEq<B>,
+    SA: VecStorage<A> + ?Sized,
 {
     #[inline]
     fn eq(&self, other: &[B; N]) -> bool {
@@ -1527,9 +1599,11 @@ where
     }
 }
 
-impl<A, B, SA: VecStorage<A> + ?Sized, const N: usize> PartialEq<&[B; N]> for VecInner<A, SA>
+impl<A, B, LenTA, SA, const N: usize> PartialEq<&[B; N]> for VecInner<A, LenTA, SA>
 where
     A: PartialEq<B>,
+    LenTA: LenType,
+    SA: VecStorage<A> + ?Sized,
 {
     #[inline]
     fn eq(&self, other: &&[B; N]) -> bool {
@@ -1537,9 +1611,11 @@ where
     }
 }
 
-impl<A, B, SA: VecStorage<A> + ?Sized> PartialEq<[B]> for VecInner<A, SA>
+impl<A, B, LenTA, SA> PartialEq<[B]> for VecInner<A, LenTA, SA>
 where
     A: PartialEq<B>,
+    LenTA: LenType,
+    SA: VecStorage<A> + ?Sized,
 {
     #[inline]
     fn eq(&self, other: &[B]) -> bool {
@@ -1547,9 +1623,11 @@ where
     }
 }
 
-impl<A, B, SA: VecStorage<A> + ?Sized> PartialEq<&[B]> for VecInner<A, SA>
+impl<A, B, LenTA, SA> PartialEq<&[B]> for VecInner<A, LenTA, SA>
 where
     A: PartialEq<B>,
+    LenTA: LenType,
+    SA: VecStorage<A> + ?Sized,
 {
     #[inline]
     fn eq(&self, other: &&[B]) -> bool {
@@ -1557,9 +1635,11 @@ where
     }
 }
 
-impl<A, B, SA: VecStorage<A> + ?Sized> PartialEq<&mut [B]> for VecInner<A, SA>
+impl<A, B, LenTA, SA> PartialEq<&mut [B]> for VecInner<A, LenTA, SA>
 where
     A: PartialEq<B>,
+    LenTA: LenType,
+    SA: VecStorage<A> + ?Sized,
 {
     #[inline]
     fn eq(&self, other: &&mut [B]) -> bool {
@@ -1568,19 +1648,19 @@ where
 }
 
 // Implements Eq if underlying data is Eq
-impl<T, S: VecStorage<T> + ?Sized> Eq for VecInner<T, S> where T: Eq {}
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> Eq for VecInner<T, LenT, S> where T: Eq {}
 
-impl<T, SA: VecStorage<T> + ?Sized, SB: VecStorage<T> + ?Sized> PartialOrd<VecInner<T, SA>>
-    for VecInner<T, SB>
+impl<T, LenTA: LenType, LenTB: LenType, SA: VecStorage<T> + ?Sized, SB: VecStorage<T> + ?Sized>
+    PartialOrd<VecInner<T, LenTA, SA>> for VecInner<T, LenTB, SB>
 where
     T: PartialOrd,
 {
-    fn partial_cmp(&self, other: &VecInner<T, SA>) -> Option<Ordering> {
+    fn partial_cmp(&self, other: &VecInner<T, LenTA, SA>) -> Option<Ordering> {
         self.as_slice().partial_cmp(other.as_slice())
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> Ord for VecInner<T, S>
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> Ord for VecInner<T, LenT, S>
 where
     T: Ord,
 {
@@ -1590,7 +1670,7 @@ where
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> ops::Deref for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> ops::Deref for VecInner<T, LenT, S> {
     type Target = [T];
 
     fn deref(&self) -> &Self::Target {
@@ -1598,52 +1678,52 @@ impl<T, S: VecStorage<T> + ?Sized> ops::Deref for VecInner<T, S> {
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> ops::DerefMut for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> ops::DerefMut for VecInner<T, LenT, S> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         self.as_mut_slice()
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> borrow::Borrow<[T]> for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> borrow::Borrow<[T]> for VecInner<T, LenT, S> {
     fn borrow(&self) -> &[T] {
         self.as_slice()
     }
 }
-impl<T, S: VecStorage<T> + ?Sized> borrow::BorrowMut<[T]> for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> borrow::BorrowMut<[T]> for VecInner<T, LenT, S> {
     fn borrow_mut(&mut self) -> &mut [T] {
         self.as_mut_slice()
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> AsRef<Self> for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> AsRef<Self> for VecInner<T, LenT, S> {
     #[inline]
     fn as_ref(&self) -> &Self {
         self
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> AsMut<Self> for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> AsMut<Self> for VecInner<T, LenT, S> {
     #[inline]
     fn as_mut(&mut self) -> &mut Self {
         self
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> AsRef<[T]> for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> AsRef<[T]> for VecInner<T, LenT, S> {
     #[inline]
     fn as_ref(&self) -> &[T] {
         self
     }
 }
 
-impl<T, S: VecStorage<T> + ?Sized> AsMut<[T]> for VecInner<T, S> {
+impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> AsMut<[T]> for VecInner<T, LenT, S> {
     #[inline]
     fn as_mut(&mut self) -> &mut [T] {
         self
     }
 }
 
-impl<T, const N: usize> Clone for Vec<T, N>
+impl<T, const N: usize, LenT: LenType> Clone for Vec<T, N, LenT>
 where
     T: Clone,
 {
@@ -1726,7 +1806,7 @@ mod tests {
         {
             let v: Vec<Droppable, 2> = Vec::new();
             let v: Box<Vec<Droppable, 2>> = Box::new(v);
-            let mut v: Box<VecView<Droppable>> = v;
+            let mut v: Box<VecView<Droppable, u8>> = v;
             v.push(Droppable::new()).ok().unwrap();
             v.push(Droppable::new()).ok().unwrap();
             assert_eq!(Droppable::count(), 2);
@@ -1739,7 +1819,7 @@ mod tests {
         {
             let v: Vec<Droppable, 2> = Vec::new();
             let v: Box<Vec<Droppable, 2>> = Box::new(v);
-            let mut v: Box<VecView<Droppable>> = v;
+            let mut v: Box<VecView<Droppable, u8>> = v;
             v.push(Droppable::new()).ok().unwrap();
             v.push(Droppable::new()).ok().unwrap();
             assert_eq!(Droppable::count(), 2);


Reviews:
user: login: diondokter
body: Not a full review from me, I've not read every line. This is a *fun* change and really cool. I do have some concerns though
state: COMMENTED
author_association: NONE
submitted_at: 2024-07-18T20:40:50Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-07-18T20:49:12Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-07-18T20:54:04Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-07-18T21:46:23Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-07-19T14:33:12Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-07-19T15:03:22Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-07-19T15:03:43Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-07-19T15:06:40Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-07-19T15:11:21Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-07-19T15:12:47Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-07-19T15:14:44Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-07-19T15:20:18Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-07-19T15:24:36Z
user: login: Sunshine40
state: COMMENTED
author_association: NONE
submitted_at: 2024-07-28T11:41:07Z
user: login: Sunshine40
state: COMMENTED
author_association: NONE
submitted_at: 2024-07-28T12:05:50Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-07-29T08:44:18Z
user: login: max-heller
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-06T13:42:28Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T14:18:09Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-06T16:18:45Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-06T16:21:19Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-06T16:31:12Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-06T16:36:16Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-06T16:37:11Z
user: login: reitermarkus
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-06T16:41:27Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T10:16:32Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T10:16:40Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T10:16:45Z
user: login: GnomedDev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T10:16:52Z
user: login: reitermarkus
state: DISMISSED
author_association: MEMBER
submitted_at: 2025-04-08T21:49:21Z
user: login: reitermarkus
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-10T17:44:15Z

Review comments:
diff_hunk: @@ -348,24 +373,29 @@ impl<T> VecView<T> {
         // the hole, and the vector length is restored to the new length.
         //
         let len = self.len();
-        let Range { start, end } = crate::slice::range(range, ..len);
+        let Range { start, end } = crate::slice::range(range, ..len.into_usize());
 
         unsafe {
             // Set `self.vec` length's to `start`, to be safe in case `Drain` is leaked.
-            self.set_len(start);
+            self.set_len(LenT::from_usize(start));
             let vec = NonNull::from(self);
             let range_slice = slice::from_raw_parts(vec.as_ref().as_ptr().add(start), end - start);
             Drain {
-                tail_start: end,
-                tail_len: len - end,
+                tail_start: LenT::from_usize(end),
+                tail_len: LenT::from_usize(len.into_usize() - end),
                 iter: range_slice.iter(),
                 vec,
             }
         }
     }
 }
 
-impl<T, S: Storage> VecInner<T, S> {
+impl<T, LenT: LenType, S: Storage> VecInner<T, LenT, S> {
+    /// Returns the length of the vector.
+    pub fn len(&self) -> LenT {
path: src/vec/mod.rs
user: login: diondokter
body: I feel like `len` should always return a usize since all other APIs do this. It's often used to index into things, so in practice this is probably almost always cast to a usize immediately.

Also, this would make changing the length of a vector a potentially very annoying breaking change
created_at: 2024-07-18T20:29:23Z
author_association: NONE
diff_hunk: @@ -528,13 +568,16 @@ impl<T, S: Storage> VecInner<T, S> {
         // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
         debug_assert!(!self.is_full());
 
-        *self.buffer.borrow_mut().get_unchecked_mut(self.len) = MaybeUninit::new(item);
+        *self
+            .buffer
+            .borrow_mut()
+            .get_unchecked_mut(self.len.into_usize()) = MaybeUninit::new(item);
 
-        self.len += 1;
+        self.len += LenT::ONE;
     }
 
     /// Shortens the vector, keeping the first `len` elements and dropping the rest.
-    pub fn truncate(&mut self, len: usize) {
+    pub fn truncate(&mut self, len: LenT) {
path: src/vec/mod.rs
user: login: diondokter
body: Same here and many other functions, I think it'd be weird if all these API's don't use usize.
created_at: 2024-07-18T20:31:41Z
author_association: NONE
diff_hunk: @@ -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);
path: src/len_type.rs
user: login: diondokter
body: Oh this is quite fun!
I wonder if there's a way to cover all numbers without breaking the compiler :P
created_at: 2024-07-18T20:36:33Z
author_association: NONE
diff_hunk: @@ -528,13 +568,16 @@ impl<T, S: Storage> VecInner<T, S> {
         // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
         debug_assert!(!self.is_full());
 
-        *self.buffer.borrow_mut().get_unchecked_mut(self.len) = MaybeUninit::new(item);
+        *self
+            .buffer
+            .borrow_mut()
+            .get_unchecked_mut(self.len.into_usize()) = MaybeUninit::new(item);
 
-        self.len += 1;
+        self.len += LenT::ONE;
     }
 
     /// Shortens the vector, keeping the first `len` elements and dropping the rest.
-    pub fn truncate(&mut self, len: usize) {
+    pub fn truncate(&mut self, len: LenT) {
path: src/vec/mod.rs
user: login: GnomedDev
body: Okay, so revert the changes made to arguments and return types as said in the PR description. Got it.
created_at: 2024-07-18T20:49:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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);
path: src/len_type.rs
user: login: GnomedDev
body: This doesn't actually cause too much stress on the compiler, it's surprising how fast the trait resolver is. From my knowledge (and I have done quite a bit of advanced type system logic, see https://github.com/GnomedDev/aformat) this is the only possible stable way to do this.

Since these containers probably shouldn't be used for N values above u8::MAX, let alone u16::MAX, I'm sure this will be fine, especially with the `diagnostic::on_unimplemented` making it super easy for users to fix.
![image](https://github.com/user-attachments/assets/262d0196-92a6-4e61-8bcf-cea5648a0e95)

created_at: 2024-07-18T20:54:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -528,13 +568,16 @@ impl<T, S: Storage> VecInner<T, S> {
         // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
         debug_assert!(!self.is_full());
 
-        *self.buffer.borrow_mut().get_unchecked_mut(self.len) = MaybeUninit::new(item);
+        *self
+            .buffer
+            .borrow_mut()
+            .get_unchecked_mut(self.len.into_usize()) = MaybeUninit::new(item);
 
-        self.len += 1;
+        self.len += LenT::ONE;
     }
 
     /// Shortens the vector, keeping the first `len` elements and dropping the rest.
-    pub fn truncate(&mut self, len: usize) {
+    pub fn truncate(&mut self, len: LenT) {
path: src/vec/mod.rs
user: login: GnomedDev
body: Done.
created_at: 2024-07-18T21:46:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -152,25 +162,40 @@ impl<T, const N: usize> Vec<T, N> {
 
         if N == M {
             Self {
-                len: N,
+                len: LenType::from_usize(N),
                 // NOTE(unsafe) ManuallyDrop<[T; M]> and [MaybeUninit<T>; N]
                 // have the same layout when N == M.
                 buffer: unsafe { mem::transmute_copy(&src) },
             }
         } else {
-            let mut v = Vec::<T, N>::new();
+            let mut v = Vec::<T, N, LenT>::new();
 
             for (src_elem, dst_elem) in src.iter().zip(v.buffer.iter_mut()) {
                 // NOTE(unsafe) src element is not going to drop as src itself
                 // is wrapped in a ManuallyDrop.
                 dst_elem.write(unsafe { ptr::read(src_elem) });
             }
 
-            v.len = M;
+            unsafe { v.set_len(M) };
             v
         }
     }
 
+    /// Casts the `LenT` type to a new type, preserving everything else about the vector.
+    ///
+    /// This can be useful if you need to pass a `Vec<T, N, u8>` into a `Vec<T, N, usize>` for example.
+    ///
+    /// This will check at compile time if the `N` value will fit into `NewLenT`, and error if not.
+    pub fn cast_len_type<NewLenT: LenType>(self) -> Vec<T, N, NewLenT> {
+        const { check_capacity_fits::<NewLenT, N>() }
+        let this = ManuallyDrop::new(self);
+
+        Vec {
+            len: NewLenT::from_usize(this.len()),
+            buffer: unsafe { ptr::read(&this.buffer) },
path: src/vec/mod.rs
user: login: reitermarkus
body: Please document why this is safe.
created_at: 2024-07-19T14:33:11Z
author_association: MEMBER
diff_hunk: @@ -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")
path: src/len_type.rs
user: login: reitermarkus
body: ```suggestion
    assert!(LenT::MAX >= N, "The capacity is larger than `LenT` can hold, increase the size of `LenT` or reduce the capacity")
```
created_at: 2024-07-19T15:03:22Z
author_association: MEMBER
diff_hunk: @@ -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",
path: src/len_type.rs
user: login: reitermarkus
body: ```suggestion
    message = "Length `N` does not have a default `LenType` mapping",
```
created_at: 2024-07-19T15:03:43Z
author_association: MEMBER
diff_hunk: @@ -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.
path: src/len_type.rs
user: login: reitermarkus
body: ```suggestion
    /// The maximum value of this type, as a `usize`.
```
created_at: 2024-07-19T15:06:40Z
author_association: MEMBER
diff_hunk: @@ -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>;
path: src/len_type.rs
user: login: reitermarkus
body: ```suggestion
#[non_exhaustive]
pub struct Const<const N: usize>;
```

Also needs to be documented.
created_at: 2024-07-19T15:11:21Z
author_association: MEMBER
diff_hunk: @@ -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 {
path: src/len_type.rs
user: login: reitermarkus
body: I'd remove `Default` from the naming here. Maybe something like `SmallestLenType::Type`?
created_at: 2024-07-19T15:12:47Z
author_association: MEMBER
diff_hunk: @@ -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;
path: src/len_type.rs
user: login: reitermarkus
body: Needs to be documented.
created_at: 2024-07-19T15:14:44Z
author_association: MEMBER
diff_hunk: @@ -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) })
path: src/string/mod.rs
user: login: reitermarkus
body: Document why this is safe.
created_at: 2024-07-19T15:20:18Z
author_association: MEMBER
diff_hunk: @@ -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>;
path: src/len_type.rs
user: login: GnomedDev
body: This is not publicly accessible, as the surrounding module is private and it is not re-exported. I have added documentation anyway though.
created_at: 2024-07-19T15:24:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -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);
path: src/len_type.rs
user: login: Sunshine40
body: In fact, if you'd like to go further about space efficiency, you can use less than a whole byte for cases where capacity < 255 by using enums with fewer variants, so that niche optimization could encode enum discriminants into the unused bit patterns.

On the other hand, with element type `T`'s alignment > 1, it's often easier to find space in the padding bytes than to squeeze space from the actual `LenType`, but with the current default behavior of the type system ([the contents of padding bytes are unspecified rather than fixed](https://internals.rust-lang.org/t/missed-layout-optimization/20045/2)), I don't know the idiomatic way to let the container make its padding bytes specified.
created_at: 2024-07-28T11:41:07Z
author_association: NONE
diff_hunk: @@ -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);
path: src/len_type.rs
user: login: Sunshine40
body: A possible approach would be to make `(T, ZeroPad)` a `LenType` with the same behavior as `<T as LenType>`
created_at: 2024-07-28T12:05:50Z
author_association: NONE
diff_hunk: @@ -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);
path: src/len_type.rs
user: login: GnomedDev
body: This could be a future PR, but I'm trying to get this initial massive improvement before we start working on niche opt stuff.
created_at: 2024-07-29T08:44:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+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 maximum 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()
path: src/len_type.rs
user: login: max-heller
body: Could this be implemented in the macro expansion as `self as usize` to avoid the possibility of a panicking codepath given that `u8`, `u16`, `usize`, and `u32` (on 32/64bit targets) all fit in a `usize`?
created_at: 2025-04-06T13:42:28Z
author_association: NONE
diff_hunk: @@ -0,0 +1,112 @@
+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 maximum 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()
path: src/len_type.rs
user: login: GnomedDev
body: I would expect rustc to know that already and not emit a panic branch in release mode, I prefer to avoid `as` conversions when possible.
created_at: 2025-04-06T14:18:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+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:
path: src/len_type.rs
user: login: reitermarkus
body: Leave this trait empty, and move all the implementation details into `Sealed`.
created_at: 2025-04-06T16:18:45Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+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 maximum 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()
path: src/len_type.rs
user: login: reitermarkus
body: Yes, this should be optimized in release mode, but maybe add an `#[inline]` here as well.
created_at: 2025-04-06T16:21:19Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+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>
path: src/len_type.rs
user: login: reitermarkus
body: Also move all of these to the `Sealed` trait.
created_at: 2025-04-06T16:31:12Z
author_association: MEMBER
diff_hunk: @@ -229,9 +232,11 @@ 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> {
path: src/string/mod.rs
user: login: reitermarkus
body: This can just use `usize`, unless you plan on also making `StringInner` generic.
created_at: 2025-04-06T16:36:16Z
author_association: MEMBER
diff_hunk: @@ -229,9 +232,11 @@ 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> {
path: src/string/mod.rs
user: login: reitermarkus
body: Ah, nevermind, the `Vec` can be generic even if `StringInner` isn't.
created_at: 2025-04-06T16:37:11Z
author_association: MEMBER
diff_hunk: @@ -19,25 +21,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(..);
path: src/vec/drain.rs
user: login: reitermarkus
body: This example is kind of useless, might as well remove it given `Vec::drain` has a better one.

created_at: 2025-04-06T16:41:27Z
author_association: MEMBER
diff_hunk: @@ -19,25 +21,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(..);
path: src/vec/drain.rs
user: login: GnomedDev
body: True, removed.
created_at: 2025-04-07T10:16:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+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:
path: src/len_type.rs
user: login: GnomedDev
body: Done.
created_at: 2025-04-07T10:16:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+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>
path: src/len_type.rs
user: login: GnomedDev
body: Done.
created_at: 2025-04-07T10:16:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+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 maximum 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()
path: src/len_type.rs
user: login: GnomedDev
body: Done.
created_at: 2025-04-07T10:16:52Z
author_association: CONTRIBUTOR

PR comments:
user: login: t-moe
created_at: 2024-07-18T21:50:45Z
body: May I ask what your motivation is for this change? Do you have any real-world use cases for it?

This seems like a premature optimization to me, and it might confuse users who are new to Rust, especially when they need to specify the full type of Vec.

If this change is necessary, a better approach might be to add LenT only to VecInner and let Vec use it with LenT=usize. This would keep the API simple while still allowing advanced users to leverage VecInner when needed.
author_association: NONE
user: login: GnomedDev
created_at: 2024-07-18T22:29:31Z
body: I have been interested in performing this kind of optimization to a stack array for a while, and in-fact have a PR open to `arrayvec` to implement this, but the case that pushed me over the edge was `embedded-tls`'s usage of many 1 byte large `T`s in nested `Vec`'s in enums leading to `160` bytes of data to be take up `328` bytes of storage.

Users who are new to Rust will most likely not hit this, as they will not be generic over the length type and therefore will get the exact same experience due to the default. If they do stray into being generic or using large N values, it is explained in documentation and in the error message what to do (pick the smallest integer type for your N, or usize).
author_association: CONTRIBUTOR
user: login: GnomedDev
created_at: 2024-07-19T15:27:41Z
body: Sorted out all of your review comments, @reitermarkus!
author_association: CONTRIBUTOR
user: login: YuhanLiin
created_at: 2024-07-25T05:59:17Z
body: Interestingly, I made a similar MR in #204 2 years ago, but it was rejected for complexity. 
author_association: CONTRIBUTOR
user: login: GnomedDev
created_at: 2024-07-25T10:35:55Z
body: It doesn't look like it was rejected for complexity, although that PR is significantly more complex due to typenum bounds, it was just closed because of the migration to const generics.
author_association: CONTRIBUTOR
user: login: reitermarkus
created_at: 2025-04-05T23:40:10Z
body: @GnomedDev, sorry for the long wait. Can you have a look at rebasing this?
author_association: MEMBER
user: login: GnomedDev
created_at: 2025-04-05T23:43:22Z
body: I'll take a look at rebasing it in the next week, if I don't get around to it after that time feel free to close or take over this PR.
author_association: CONTRIBUTOR
user: login: GnomedDev
created_at: 2025-04-06T10:55:13Z
body: It looks like this PR is going to have to be practically rewritten due to the VecStorage change... but I'll see if I can do that.
author_association: CONTRIBUTOR
user: login: GnomedDev
created_at: 2025-04-06T13:33:08Z
body: @reitermarkus Done, please note that I just did this from scratch instead of rebasing as it was conflicting so much, so keep that in mind while reviewing.
author_association: CONTRIBUTOR
user: login: reitermarkus
created_at: 2025-04-08T21:59:24Z
body: @GnomedDev, needs another rebase, but should be good to go after that.

> Adding the length generic to `VecView`, this can be changed to only store `usize` at the cost of only `Vec<T, N, usize>` being able to unsize (or requiring a `Vec::cast_len_type` call before unsizing, at least).

I'm quite split on this: If `VecView` only supports `usize`, it's easier to use, but then `Vec` will have to use `usize` by default or it gets confusing, so the space-saving becomes opt-in. I sightly prefer the space-saving by default, since it applies to the most common sizes with `N < 256`, and keeping `Vec` and `VecView` more consistent.
author_association: MEMBER
user: login: GnomedDev
created_at: 2025-04-10T16:57:45Z
body: @reitermarkus I've rebased, happy for this to finally get merged in.
author_association: CONTRIBUTOR
user: login: reitermarkus
created_at: 2025-04-10T17:51:31Z
body: Thanks!
author_association: MEMBER