Skip to content

Commit

Permalink
Merge pull request #352 from rjsberry/impl-vec-from-array
Browse files Browse the repository at this point in the history
Impl conversion from array to Vec
  • Loading branch information
Dirbaio committed Jan 1, 2024
2 parents 49cc30d + 0a5fd1d commit e23e9b6
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `format` macro.
- Added `String::from_utf16`.
- Added `is_full`, `recent_index`, `oldest`, and `oldest_index` to `HistoryBuffer`
- Added infallible conversions from arrays to `Vec`.

### Changed

Expand Down
5 changes: 5 additions & 0 deletions src/sealed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ pub(crate) const fn smaller_than<const N: usize, const MAX: usize>() {
Assert::<N, MAX>::LESS;
}

#[allow(dead_code, path_statements, clippy::no_effect)]
pub(crate) const fn greater_than_eq<const N: usize, const MIN: usize>() {
Assert::<N, MIN>::GREATER_EQ;
}

#[allow(dead_code, path_statements, clippy::no_effect)]
pub(crate) const fn greater_than_eq_0<const N: usize>() {
Assert::<N, 0>::GREATER_EQ;
Expand Down
86 changes: 85 additions & 1 deletion src/vec.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
use core::{cmp::Ordering, fmt, hash, iter::FromIterator, mem::MaybeUninit, ops, ptr, slice};
use core::{
cmp::Ordering,
fmt, hash,
iter::FromIterator,
mem,
mem::{ManuallyDrop, MaybeUninit},
ops, ptr, slice,
};

/// A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html).
///
Expand Down Expand Up @@ -85,6 +92,45 @@ impl<T, const N: usize> Vec<T, N> {
Ok(v)
}

/// Constructs a new vector with a fixed capacity of `N`, initializing
/// it with the provided array.
///
/// The length of the provided array, `M` may be equal to _or_ less than
/// the capacity of the vector, `N`.
///
/// If the length of the provided array is greater than the capacity of the
/// vector a compile-time error will be produced.
pub fn from_array<const M: usize>(src: [T; M]) -> Self {
// Const assert M >= 0
crate::sealed::greater_than_eq_0::<M>();
// Const assert N >= M
crate::sealed::greater_than_eq::<N, M>();

// We've got to copy `src`, but we're functionally moving it. Don't run
// any Drop code for T.
let src = ManuallyDrop::new(src);

if N == M {
Self {
len: 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();

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;
v
}
}

/// Clones a vec into a new vec
pub(crate) fn clone(&self) -> Self
where
Expand Down Expand Up @@ -858,6 +904,12 @@ impl<T, const N: usize> Drop for Vec<T, N> {
}
}

impl<T, const N: usize, const M: usize> From<[T; M]> for Vec<T, N> {
fn from(array: [T; M]) -> Self {
Self::from_array(array)
}
}

impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec<T, N> {
type Error = ();

Expand Down Expand Up @@ -1533,6 +1585,38 @@ mod tests {
assert!(Vec::<u8, 2>::from_slice(&[1, 2, 3]).is_err());
}

#[test]
fn from_array() {
// Successful construction, N == M
let v: Vec<u8, 3> = Vec::from_array([1, 2, 3]);
assert_eq!(v, Vec::<u8, 3>::from([1, 2, 3]));
assert_eq!(v.len(), 3);
assert_eq!(v.as_slice(), &[1, 2, 3]);

// Successful construction, N > M
let v: Vec<u8, 4> = Vec::from_array([1, 2, 3]);
assert_eq!(v, Vec::<u8, 4>::from([1, 2, 3]));
assert_eq!(v.len(), 3);
assert_eq!(v.as_slice(), &[1, 2, 3]);
}

#[test]
fn from_array_no_drop() {
struct Drops(Option<u8>);

impl Drop for Drops {
fn drop(&mut self) {
self.0 = None;
}
}

let v: Vec<Drops, 3> = Vec::from([Drops(Some(1)), Drops(Some(2)), Drops(Some(3))]);

assert_eq!(v[0].0, Some(1));
assert_eq!(v[1].0, Some(2));
assert_eq!(v[2].0, Some(3));
}

#[test]
fn starts_with() {
let v: Vec<_, 8> = Vec::from_slice(b"ab").unwrap();
Expand Down

0 comments on commit e23e9b6

Please sign in to comment.