Skip to content

Commit

Permalink
Tweak API
Browse files Browse the repository at this point in the history
  • Loading branch information
c410-f3r committed Sep 28, 2020
1 parent 437abd4 commit cbabf74
Showing 1 changed file with 23 additions and 50 deletions.
73 changes: 23 additions & 50 deletions text/2978-stack_based_vec.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,22 +86,28 @@ Of course, fixed buffers lead to some inflexibility because unlike `Vec`, the un
# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation

`ArrayVec` is a contiguous memory block where elements can be collected, threfore, a collection by definition and even though `core::collections` doesn't exist, it is the most natural module placement.
`ArrayVec` is a contiguous memory block where elements can be collected, therefore, a collection by definition and even though `core::collections` doesn't exist, it is the most natural module placement.

The API basically mimics most of the current `Vec` surface with some tweaks and additional methods to manage capacity. Notably, these additional methods are fallible versions of some well-known functions like `insert` that will return `Result` instead of panicking at run-time.
The API basically mimics most of the current `Vec` surface with some tweaks to manage capacity.

Notably, these tweaked methods are fallible versions of some well-known functions like `push` that will return `Result` instead of panicking at run-time. Since the upper capacity bound is known at compile-time, the compiler is likely going to remove most of the conditional bounding checking.

```rust
// core::collections

pub struct ArrayVec<T, const N: usize> {
data: MaybeUninit<[T; N]>,
len: usize
len: usize,
}

impl<T, const N: usize> ArrayVec<T, N> {
// Constructors

pub unsafe fn from_raw_parts(_ptr: *mut T, _len: usize) -> Self;
#[inline]
pub fn from_array(array: [T; N]) -> Self;

#[inline]
pub fn from_array_and_len(array: [T; N], len: usize) -> Self;

#[inline]
pub const fn new() -> Self;
Expand Down Expand Up @@ -140,27 +146,28 @@ impl<T, const N: usize> ArrayVec<T, N> {
where
R: RangeBounds<usize>;

pub fn extend_from_cloneable_slice(&mut self, other: &[T])
pub fn extend_from_cloneable_slice(&mut self, other: &[T]) -> Result<(), &[T]>
where
T: Clone; // Panics at run-time
T: Clone;

pub fn extend_from_copyable_slice(&mut self, other: &[T])
pub fn extend_from_copyable_slice(&mut self, other: &[T]) -> Result<(), &[T]>
where
T: Copy; // Panics at run-time
T: Copy;

pub fn insert(&mut self, idx: usize, element: T); // Panics at run-time
pub fn insert(&mut self, _idx: usize, element: T) -> Result<(), T>;

#[inline]
pub const fn is_empty(&self) -> bool;

#[inline]
pub const fn len(&self) -> usize;

pub fn pop(&mut self) -> T; // Panics at run-time
pub fn pop(&mut self) -> Option<T>;

pub fn push(&mut self, element: T); // Panics at run-time
#[inline]
pub fn push(&mut self, element: T) -> Result<(), T>;

pub fn remove(&mut self, idx: usize) -> T; // Panics at run-time
pub fn remove(&mut self, idx: usize) -> Option<T>;

pub fn retain<F>(&mut self, f: F)
where
Expand All @@ -176,49 +183,15 @@ impl<T, const N: usize> ArrayVec<T, N> {

pub fn split_off(&mut self, at: usize) -> Self;

pub fn swap_remove(&mut self, idx: usize) -> T; // Panics at run-time
pub fn swap_remove(&mut self, idx: usize) -> Option<T>;

pub fn truncate(&mut self, len: usize);

pub fn try_extend_from_cloneable_slice(&mut self, other: &[T]) -> Result<(), ArrayVecError>
where
T: Clone;

pub fn try_extend_from_copyable_slice(&mut self, other: &[T]) -> Result<(), ArrayVecError>
where
T: Copy;

pub fn try_insert(&mut self, _idx: usize, element: T) -> Result<(), ArrayVecError>;

pub fn try_pop(&mut self) -> Result<T, ArrayVecError>;

pub fn try_push(&mut self, element: T) -> Result<(), ArrayVecError>;

pub fn try_remove(&mut self, idx: usize) -> Result<T, ArrayVecError>;

pub fn try_swap_remove(&mut self, idx: usize) -> Result<T, ArrayVecError>;
}

#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum ArrayVecError {
CapacityOverflow,
NoElement
}

impl fmt::Display for ArrayVecError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
Self::CapacityOverflow => "It is not possible to add more elements",
Self::NoElement => "There are no elements in the vector",
};
write!(f, "{}", s)
}
}
```

Meaningless, unstable and deprecated methods like `reserve` or `drain_filter` weren't considered and in general, everything that includes or removes elements have a fallible version: `extend_from_cloneable_slice`, `extend_from_copyable_slice`, `pop`, `remove` and `swap_remove`.
Since it is known at compile-time the upper capacity bound, the compiler is likely going to remove the conditional bounding checking of the newly

A concrete implementation is available at https://github.com/c410-f3r/stack-based-vec.
Meaningless, unstable and deprecated methods like `reserve` or `drain_filter` weren't considered. A concrete implementation is available at https://github.com/c410-f3r/stack-based-vec.

# Drawbacks
[drawbacks]: #drawbacks
Expand All @@ -229,7 +202,7 @@ New and existing users are likely to find it difficult to differentiate the purp

### The current ecosystem is fine

Even with all the fragmentation, different types of memory usage is an overkill in certain situations. If someone wants to use stack memory in an embedded application, then it is just a matter of grabbing an appropriated crate.
`ArrayVec` might be an overkill in certain situations. If someone wants to use stack memory in a specific application, then it is just a matter of grabbing the appropriated crate.

# Prior art
[prior-art]: #prior-art
Expand Down

0 comments on commit cbabf74

Please sign in to comment.