Skip to content

Commit e23e9b6

Browse files
authored
Merge pull request #352 from rjsberry/impl-vec-from-array
Impl conversion from array to Vec
2 parents 49cc30d + 0a5fd1d commit e23e9b6

File tree

3 files changed

+91
-1
lines changed

3 files changed

+91
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1212
- Added `format` macro.
1313
- Added `String::from_utf16`.
1414
- Added `is_full`, `recent_index`, `oldest`, and `oldest_index` to `HistoryBuffer`
15+
- Added infallible conversions from arrays to `Vec`.
1516

1617
### Changed
1718

src/sealed.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ pub(crate) const fn smaller_than<const N: usize, const MAX: usize>() {
33
Assert::<N, MAX>::LESS;
44
}
55

6+
#[allow(dead_code, path_statements, clippy::no_effect)]
7+
pub(crate) const fn greater_than_eq<const N: usize, const MIN: usize>() {
8+
Assert::<N, MIN>::GREATER_EQ;
9+
}
10+
611
#[allow(dead_code, path_statements, clippy::no_effect)]
712
pub(crate) const fn greater_than_eq_0<const N: usize>() {
813
Assert::<N, 0>::GREATER_EQ;

src/vec.rs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
use core::{cmp::Ordering, fmt, hash, iter::FromIterator, mem::MaybeUninit, ops, ptr, slice};
1+
use core::{
2+
cmp::Ordering,
3+
fmt, hash,
4+
iter::FromIterator,
5+
mem,
6+
mem::{ManuallyDrop, MaybeUninit},
7+
ops, ptr, slice,
8+
};
29

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

95+
/// Constructs a new vector with a fixed capacity of `N`, initializing
96+
/// it with the provided array.
97+
///
98+
/// The length of the provided array, `M` may be equal to _or_ less than
99+
/// the capacity of the vector, `N`.
100+
///
101+
/// If the length of the provided array is greater than the capacity of the
102+
/// vector a compile-time error will be produced.
103+
pub fn from_array<const M: usize>(src: [T; M]) -> Self {
104+
// Const assert M >= 0
105+
crate::sealed::greater_than_eq_0::<M>();
106+
// Const assert N >= M
107+
crate::sealed::greater_than_eq::<N, M>();
108+
109+
// We've got to copy `src`, but we're functionally moving it. Don't run
110+
// any Drop code for T.
111+
let src = ManuallyDrop::new(src);
112+
113+
if N == M {
114+
Self {
115+
len: N,
116+
// NOTE(unsafe) ManuallyDrop<[T; M]> and [MaybeUninit<T>; N]
117+
// have the same layout when N == M.
118+
buffer: unsafe { mem::transmute_copy(&src) },
119+
}
120+
} else {
121+
let mut v = Vec::<T, N>::new();
122+
123+
for (src_elem, dst_elem) in src.iter().zip(v.buffer.iter_mut()) {
124+
// NOTE(unsafe) src element is not going to drop as src itself
125+
// is wrapped in a ManuallyDrop.
126+
dst_elem.write(unsafe { ptr::read(src_elem) });
127+
}
128+
129+
v.len = M;
130+
v
131+
}
132+
}
133+
88134
/// Clones a vec into a new vec
89135
pub(crate) fn clone(&self) -> Self
90136
where
@@ -858,6 +904,12 @@ impl<T, const N: usize> Drop for Vec<T, N> {
858904
}
859905
}
860906

907+
impl<T, const N: usize, const M: usize> From<[T; M]> for Vec<T, N> {
908+
fn from(array: [T; M]) -> Self {
909+
Self::from_array(array)
910+
}
911+
}
912+
861913
impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec<T, N> {
862914
type Error = ();
863915

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

1588+
#[test]
1589+
fn from_array() {
1590+
// Successful construction, N == M
1591+
let v: Vec<u8, 3> = Vec::from_array([1, 2, 3]);
1592+
assert_eq!(v, Vec::<u8, 3>::from([1, 2, 3]));
1593+
assert_eq!(v.len(), 3);
1594+
assert_eq!(v.as_slice(), &[1, 2, 3]);
1595+
1596+
// Successful construction, N > M
1597+
let v: Vec<u8, 4> = Vec::from_array([1, 2, 3]);
1598+
assert_eq!(v, Vec::<u8, 4>::from([1, 2, 3]));
1599+
assert_eq!(v.len(), 3);
1600+
assert_eq!(v.as_slice(), &[1, 2, 3]);
1601+
}
1602+
1603+
#[test]
1604+
fn from_array_no_drop() {
1605+
struct Drops(Option<u8>);
1606+
1607+
impl Drop for Drops {
1608+
fn drop(&mut self) {
1609+
self.0 = None;
1610+
}
1611+
}
1612+
1613+
let v: Vec<Drops, 3> = Vec::from([Drops(Some(1)), Drops(Some(2)), Drops(Some(3))]);
1614+
1615+
assert_eq!(v[0].0, Some(1));
1616+
assert_eq!(v[1].0, Some(2));
1617+
assert_eq!(v[2].0, Some(3));
1618+
}
1619+
15361620
#[test]
15371621
fn starts_with() {
15381622
let v: Vec<_, 8> = Vec::from_slice(b"ab").unwrap();

0 commit comments

Comments
 (0)