rust-embedded / heapless

Heapless, `static` friendly data structures
Apache License 2.0
1.56k stars 185 forks source link

Make the type of `heapless::vec::VecInner`'s `len` field generic and default to `usize` #506

Open Sunshine40 opened 3 months ago

Sunshine40 commented 3 months ago

Motivation

Currently, heapless::String<33> takes 48 bytes and Option<heapless::String<33>> takes 56 bytes on 64-bit target platforms.

We could save up to 14 / 21 bytes respectively and remove the align(8) requirement if we allow using user-specified types such as u8 to represent the occupied length. heapless::String<33> could even allow niche optimization if a enum with only 34 variants can be used as the type of field len in heapless::vec::VecInner<u8, OwnedStorage<33>>.

Implementation

Since the API should resemble alloc::Vec which uses usizes everywhere to represent length / capacity / offset, we need to define a trait for an arbitrary type to interop with usize.

And I think the TrustedStep trait in nightly std could be a good start.

We could make a replica of the trait and it's impls for std types so the trait could be used in stable Rust.

Then we define the following traits:

pub trait Offset: Step {
    /// The value to represent "zero size" or "no offset"
    const ZERO: Self;
    /// The number of *successor* steps required to get from `Self::Zero` to the max possible `Self` value.
    const MAX: usize;

    /// # Invariants
    ///
    /// This should be infallible and produce the same result as `Step::steps_between(&Self::ZERO, self).unwrap()`
    /// which means `Self::ZERO` is the min possible `Self` value.
    fn to_usize(&self) -> usize {
        Step::steps_between(&Self::ZERO, self).unwrap()
    }

    /// # Invariants
    ///
    /// This should produce the same result as `Step::forward_checked(Self::ZERO, value)`
    fn from_usize(value: usize) -> Option<Self> {
        Step::forward_checked(Self::ZERO, value)
    }
}

/// A type that upholds all invariants of [`Offset`].
///
/// # Safety
///
/// The implementation of [`Offset`] for the given type must guarantee all
/// invariants of all methods are upheld. See the [`Offset`] trait's documentation
/// for details. Consumers are free to rely on the invariants in unsafe code.
pub unsafe trait TrustedOffset: Offset + TrustedStep {}

and the TrustedOffset trait should provide what we need to implement heapless::vec::VecInner with.

Dirbaio commented 3 months ago

isn't this #504?