Skip to content

Commit c2453e5

Browse files
authored
Merge pull request bluss#177 from bluss/length-32-bit
Use u32 for the length field in arrayvec
2 parents dfd882b + feb9928 commit c2453e5

File tree

5 files changed

+71
-25
lines changed

5 files changed

+71
-25
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ Recent Changes (arrayvec)
1010

1111
The New type syntax is `ArrayVec<T, CAP>` where `CAP` is the arrayvec capacity.
1212
For arraystring the syntax is `ArrayString<CAP>`.
13-
Change by @bluss.
13+
14+
Length is stored internally as u32; this limits the maximum capacity. The size
15+
of the `ArrayVec` or `ArrayString` structs for the same capacity may grow
16+
slightly compared with the previous version (depending on padding requirements
17+
for the element type). Change by @bluss.
1418

1519
- Arrayvec's `.extend()` and `FromIterator`/`.collect()` to arrayvec now
1620
**panic** if the capacity of the arrayvec is exceeded. Change by @bluss.

src/array_string.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,28 @@ use std::str::FromStr;
1212
use std::str::Utf8Error;
1313

1414
use crate::CapacityError;
15+
use crate::LenUint;
1516
use crate::char::encode_utf8;
1617

1718
#[cfg(feature="serde")]
1819
use serde::{Serialize, Deserialize, Serializer, Deserializer};
1920

21+
2022
/// A string with a fixed capacity.
2123
///
2224
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
23-
/// of its length.
25+
/// of its length, and is parameterized by `CAP` for the maximum capacity.
26+
///
27+
/// `CAP` is of type `usize` but is range limited to `u32::MAX`; attempting to create larger
28+
/// arrayvecs with larger capacity will panic.
2429
///
2530
/// The string is a contiguous value that you can store directly on the stack
2631
/// if needed.
2732
#[derive(Copy)]
2833
pub struct ArrayString<const CAP: usize> {
2934
// the `len` first elements of the array are initialized
3035
xs: [MaybeUninit<u8>; CAP],
31-
len: usize,
36+
len: LenUint,
3237
}
3338

3439
impl<const CAP: usize> Default for ArrayString<CAP>
@@ -55,21 +60,23 @@ impl<const CAP: usize> ArrayString<CAP>
5560
/// ```
5661
#[cfg(not(feature="unstable-const-fn"))]
5762
pub fn new() -> ArrayString<CAP> {
63+
assert_capacity_limit!(CAP);
5864
unsafe {
5965
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
6066
}
6167
}
6268

6369
#[cfg(feature="unstable-const-fn")]
6470
pub const fn new() -> ArrayString<CAP> {
71+
assert_capacity_limit!(CAP);
6572
unsafe {
6673
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
6774
}
6875
}
6976

7077
/// Return the length of the string.
7178
#[inline]
72-
pub fn len(&self) -> usize { self.len }
79+
pub fn len(&self) -> usize { self.len as usize }
7380

7481
/// Returns whether the string is empty.
7582
#[inline]
@@ -347,8 +354,9 @@ impl<const CAP: usize> ArrayString<CAP>
347354
/// This method uses *debug assertions* to check the validity of `length`
348355
/// and may use other debug assertions.
349356
pub unsafe fn set_len(&mut self, length: usize) {
357+
// type invariant that capacity always fits in LenUint
350358
debug_assert!(length <= self.capacity());
351-
self.len = length;
359+
self.len = length as LenUint;
352360
}
353361

354362
/// Return a string slice of the whole `ArrayString`.
@@ -371,7 +379,7 @@ impl<const CAP: usize> Deref for ArrayString<CAP>
371379
#[inline]
372380
fn deref(&self) -> &str {
373381
unsafe {
374-
let sl = slice::from_raw_parts(self.as_ptr(), self.len);
382+
let sl = slice::from_raw_parts(self.as_ptr(), self.len());
375383
str::from_utf8_unchecked(sl)
376384
}
377385
}
@@ -382,7 +390,8 @@ impl<const CAP: usize> DerefMut for ArrayString<CAP>
382390
#[inline]
383391
fn deref_mut(&mut self) -> &mut str {
384392
unsafe {
385-
let sl = slice::from_raw_parts_mut(self.as_mut_ptr(), self.len);
393+
let len = self.len();
394+
let sl = slice::from_raw_parts_mut(self.as_mut_ptr(), len);
386395
str::from_utf8_unchecked_mut(sl)
387396
}
388397
}

src/arrayvec.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::mem::MaybeUninit;
2020
#[cfg(feature="serde")]
2121
use serde::{Serialize, Deserialize, Serializer, Deserializer};
2222

23+
use crate::LenUint;
2324
use crate::errors::CapacityError;
2425
use crate::arrayvec_impl::ArrayVecImpl;
2526

@@ -29,17 +30,18 @@ use crate::arrayvec_impl::ArrayVecImpl;
2930
/// the number of initialized elements. The `ArrayVec<T, CAP>` is parameterized
3031
/// by `T` for the element type and `CAP` for the maximum capacity.
3132
///
33+
/// `CAP` is of type `usize` but is range limited to `u32::MAX`; attempting to create larger
34+
/// arrayvecs with larger capacity will panic.
35+
///
3236
/// The vector is a contiguous value (storing the elements inline) that you can store directly on
3337
/// the stack if needed.
3438
///
35-
/// It offers a simple API but also dereferences to a slice, so
36-
/// that the full slice API is available.
37-
///
38-
/// ArrayVec can be converted into a by value iterator.
39+
/// It offers a simple API but also dereferences to a slice, so that the full slice API is
40+
/// available. The ArrayVec can be converted into a by value iterator.
3941
pub struct ArrayVec<T, const CAP: usize> {
4042
// the `len` first elements of the array are initialized
4143
xs: [MaybeUninit<T>; CAP],
42-
len: usize,
44+
len: LenUint,
4345
}
4446

4547
impl<T, const CAP: usize> Drop for ArrayVec<T, CAP> {
@@ -76,13 +78,15 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
7678
/// ```
7779
#[cfg(not(feature="unstable-const-fn"))]
7880
pub fn new() -> ArrayVec<T, CAP> {
81+
assert_capacity_limit!(CAP);
7982
unsafe {
8083
ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
8184
}
8285
}
8386

8487
#[cfg(feature="unstable-const-fn")]
8588
pub const fn new() -> ArrayVec<T, CAP> {
89+
assert_capacity_limit!(CAP);
8690
unsafe {
8791
ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
8892
}
@@ -97,7 +101,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
97101
/// array.pop();
98102
/// assert_eq!(array.len(), 2);
99103
/// ```
100-
#[inline]
104+
#[inline(always)]
101105
pub fn len(&self) -> usize { self.len as usize }
102106

103107
/// Returns whether the `ArrayVec` is empty.
@@ -475,8 +479,9 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
475479
/// This method uses *debug assertions* to check that `length` is
476480
/// not greater than the capacity.
477481
pub unsafe fn set_len(&mut self, length: usize) {
482+
// type invariant that capacity always fits in LenUint
478483
debug_assert!(length <= self.capacity());
479-
self.len = length;
484+
self.len = length as LenUint;
480485
}
481486

482487
/// Copy all elements from the slice and append to the `ArrayVec`.
@@ -569,7 +574,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
569574

570575
// Calling `set_len` creates a fresh and thus unique mutable references, making all
571576
// older aliases we created invalid. So we cannot call that function.
572-
self.len = start;
577+
self.len = start as LenUint;
573578

574579
unsafe {
575580
Drain {
@@ -626,7 +631,7 @@ impl<T, const CAP: usize> ArrayVecImpl for ArrayVec<T, CAP> {
626631

627632
unsafe fn set_len(&mut self, length: usize) {
628633
debug_assert!(length <= CAP);
629-
self.len = length;
634+
self.len = length as LenUint;
630635
}
631636

632637
fn as_ptr(&self) -> *const Self::Item {
@@ -769,7 +774,7 @@ impl<T, const CAP: usize> Iterator for IntoIter<T, CAP> {
769774
type Item = T;
770775

771776
fn next(&mut self) -> Option<Self::Item> {
772-
if self.index == self.v.len {
777+
if self.index == self.v.len() {
773778
None
774779
} else {
775780
unsafe {
@@ -788,7 +793,7 @@ impl<T, const CAP: usize> Iterator for IntoIter<T, CAP> {
788793

789794
impl<T, const CAP: usize> DoubleEndedIterator for IntoIter<T, CAP> {
790795
fn next_back(&mut self) -> Option<Self::Item> {
791-
if self.index == self.v.len {
796+
if self.index == self.v.len() {
792797
None
793798
} else {
794799
unsafe {
@@ -963,7 +968,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
963968
value: &mut self.len,
964969
data: len,
965970
f: move |&len, self_len| {
966-
**self_len = len;
971+
**self_len = len as LenUint;
967972
}
968973
};
969974
let mut iter = iterable.into_iter();

src/lib.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! **arrayvec** provides the types `ArrayVec` and `ArrayString`:
1+
//! **arrayvec** provides the types [`ArrayVec`] and [`ArrayString`]:
22
//! array-backed vector and string types, which store their contents inline.
33
//!
44
//! The arrayvec package has the following cargo features:
@@ -21,16 +21,28 @@
2121
//!
2222
//! This version of arrayvec requires Rust 1.51 or later.
2323
//!
24-
#![doc(html_root_url="https://docs.rs/arrayvec/0.5/")]
24+
#![doc(html_root_url="https://docs.rs/arrayvec/0.6/")]
2525
#![cfg_attr(not(feature="std"), no_std)]
26-
#![cfg_attr(feature="unstable-const-fn", feature(const_fn, const_maybe_uninit_assume_init))]
26+
#![cfg_attr(feature="unstable-const-fn", feature(const_fn, const_maybe_uninit_assume_init, const_panic))]
2727

2828
#[cfg(feature="serde")]
2929
extern crate serde;
3030

3131
#[cfg(not(feature="std"))]
3232
extern crate core as std;
3333

34+
pub(crate) type LenUint = u32;
35+
36+
macro_rules! assert_capacity_limit {
37+
($cap:expr) => {
38+
if std::mem::size_of::<usize>() > std::mem::size_of::<LenUint>() {
39+
if CAP > LenUint::MAX as usize {
40+
panic!("ArrayVec: largest supported capacity is u32::MAX")
41+
}
42+
}
43+
}
44+
}
45+
3446
mod arrayvec_impl;
3547
mod arrayvec;
3648
mod array_string;

tests/tests.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,17 +295,17 @@ fn test_compact_size() {
295295
// 4 bytes + padding + length
296296
type ByteArray = ArrayVec<u8, 4>;
297297
println!("{}", mem::size_of::<ByteArray>());
298-
assert!(mem::size_of::<ByteArray>() <= 2 * mem::size_of::<usize>());
298+
assert!(mem::size_of::<ByteArray>() <= 2 * mem::size_of::<u32>());
299299

300300
// just length
301301
type EmptyArray = ArrayVec<u8, 0>;
302302
println!("{}", mem::size_of::<EmptyArray>());
303-
assert!(mem::size_of::<EmptyArray>() <= mem::size_of::<usize>());
303+
assert!(mem::size_of::<EmptyArray>() <= mem::size_of::<u32>());
304304

305305
// 3 elements + padding + length
306306
type QuadArray = ArrayVec<u32, 3>;
307307
println!("{}", mem::size_of::<QuadArray>());
308-
assert!(mem::size_of::<QuadArray>() <= 4 * 4 + mem::size_of::<usize>());
308+
assert!(mem::size_of::<QuadArray>() <= 4 * 4 + mem::size_of::<u32>());
309309
}
310310

311311
#[test]
@@ -711,3 +711,19 @@ fn test_try_from_argument() {
711711
let v = ArrayString::<16>::try_from(format_args!("Hello {}", 123)).unwrap();
712712
assert_eq!(&v, "Hello 123");
713713
}
714+
715+
#[test]
716+
fn allow_max_capacity_arrayvec_type() {
717+
// this type is allowed to be used (but can't be constructed)
718+
let _v: ArrayVec<(), {usize::MAX}>;
719+
}
720+
721+
#[should_panic(expected="ArrayVec: largest supported")]
722+
#[test]
723+
fn deny_max_capacity_arrayvec_value() {
724+
if mem::size_of::<usize>() <= mem::size_of::<u32>() {
725+
panic!("This test does not work on this platform. 'ArrayVec: largest supported'");
726+
}
727+
// this type is allowed to be used (but can't be constructed)
728+
let _v: ArrayVec<(), {usize::MAX}> = ArrayVec::new();
729+
}

0 commit comments

Comments
 (0)