Sign In

arrayvec

Package Overview
Dependencies
Maintainers
1
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

arrayvec - cargo Package Compare versions

Comparing version
0.4.12
to
0.5.0
+1
-1
.cargo_vcs_info.json
{
"git": {
"sha1": "f88c62e59fc130edf1185b6c33720eb4874c814a"
"sha1": "ea591bc2de5202790c600638c96efa392413001c"
}
}
language: rust
sudo: false
env:
- FEATURES='serde-1'
- FEATURES='serde'
matrix:
include:
- rust: 1.13.0
- rust: stable
- rust: 1.36.0
env:
- NODEFAULT=1
- NODROP_FEATURES='use_needs_drop'
- rust: 1.22.1
env:
- FEATURES='array-sizes-33-128 array-sizes-129-255'
- rust: stable
- rust: stable
env:
- FEATURES='serde'
- rust: stable
env:
- FEATURES='array-sizes-33-128 array-sizes-129-255'
- ARRAYVECTEST_ENSURE_MAYBEUNINIT=1
- rust: beta
- rust: nightly
env:
- NODEFAULT=1
- ARRAYVECTEST_ENSURE_UNION=1
- rust: nightly
env:
- NODROP_FEATURES='use_needs_drop'
- ARRAYVECTEST_ENSURE_MAYBEUNINIT=1
- FEATURES='serde'
- rust: nightly
env:
- FEATURES='serde use_union'
- NODROP_FEATURES='use_union'
- ARRAYVECTEST_ENSURE_MAYBEUNINIT=1
- FEATURES='array-sizes-33-128 array-sizes-129-255'
branches:

@@ -39,10 +31,9 @@ only:

- |
([ ! -z "$NODROP_FEATURES" ] || cargo build --verbose --features "$FEATURES") &&
([ "$NODEFAULT" != 1 ] || cargo build --verbose --no-default-features) &&
([ ! -z "$NODROP_FEATURES" ] || cargo test --verbose --features "$FEATURES") &&
([ ! -z "$NODROP_FEATURES" ] || cargo test --release --verbose --features "$FEATURES") &&
([ ! -z "$NODROP_FEATURES" ] || cargo bench --verbose --features "$FEATURES" -- --test) &&
([ ! -z "$NODROP_FEATURES" ] || cargo doc --verbose --features "$FEATURES") &&
([ "$NODEFAULT" != 1 ] || cargo build --verbose --manifest-path=nodrop/Cargo.toml --no-default-features) &&
cargo test --verbose --manifest-path=nodrop/Cargo.toml --features "$NODROP_FEATURES" &&
cargo bench --verbose --manifest-path=nodrop/Cargo.toml --features "$NODROP_FEATURES" -- --test
cargo build -v --no-default-features &&
cargo build -v --features "$FEATURES" &&
cargo test -v --features "$FEATURES" &&
cargo test -v --release --features "$FEATURES" &&
cargo bench -v --features "$FEATURES" --no-run &&
cargo doc -v --features "$FEATURES" &&
cargo build -v --manifest-path=nodrop/Cargo.toml &&
cargo test -v --manifest-path=nodrop/Cargo.toml

@@ -5,5 +5,8 @@

use std::io::Write;
use arrayvec::ArrayVec;
use bencher::Bencher;
use bencher::black_box;

@@ -15,4 +18,5 @@ fn extend_with_constant(b: &mut Bencher) {

v.clear();
v.extend((0..cap).map(|_| 1));
v[0]
let constant = black_box(1);
v.extend((0..cap).map(move |_| constant));
v[511]
});

@@ -27,4 +31,5 @@ b.bytes = v.capacity() as u64;

v.clear();
v.extend((0..cap).map(|x| x as _));
v[0]
let range = 0..cap;
v.extend(range.map(|x| black_box(x as _)));
v[511]
});

@@ -39,4 +44,5 @@ b.bytes = v.capacity() as u64;

v.clear();
v.extend(data.iter().cloned());
v[0]
let iter = data.iter().map(|&x| x);
v.extend(iter);
v[511]
});

@@ -46,3 +52,32 @@ b.bytes = v.capacity() as u64;

benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice);
fn extend_with_write(b: &mut Bencher) {
let mut v = ArrayVec::<[u8; 512]>::new();
let data = [1; 512];
b.iter(|| {
v.clear();
v.write(&data[..]).ok();
v[511]
});
b.bytes = v.capacity() as u64;
}
fn extend_from_slice(b: &mut Bencher) {
let mut v = ArrayVec::<[u8; 512]>::new();
let data = [1; 512];
b.iter(|| {
v.clear();
v.try_extend_from_slice(&data).ok();
v[511]
});
b.bytes = v.capacity() as u64;
}
benchmark_group!(benches,
extend_with_constant,
extend_with_range,
extend_with_slice,
extend_with_write,
extend_from_slice
);
benchmark_main!(benches);

@@ -14,4 +14,5 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

[package]
edition = "2018"
name = "arrayvec"
version = "0.4.12"
version = "0.5.0"
authors = ["bluss"]

@@ -25,3 +26,3 @@ description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString."

[package.metadata.docs.rs]
features = ["serde-1"]
features = ["serde"]

@@ -39,6 +40,2 @@ [package.metadata.release]

harness = false
[dependencies.nodrop]
version = "0.1.12"
default-features = false
[dependencies.serde]

@@ -63,4 +60,2 @@ version = "1.0"

default = ["std"]
serde-1 = ["serde"]
std = []
use_union = []

@@ -25,6 +25,23 @@

- 0.4.12
- 0.5.0 (not released yet)
- Use raw pointers instead of ``get_unchecked_mut`` where the target may be
uninitialized a everywhere relevant in the ArrayVec implementation.
- Use ``MaybeUninit`` (now unconditionally) in the implementation of
``ArrayVec``
- Use ``MaybeUninit`` (now unconditionally) in the implementation of
``ArrayString``
- The crate feature for serde serialization is now named ``serde``.
- Updated the ``Array`` trait interface, and it is now easier to use for
users outside the crate.
- Add ``FromStr`` impl for ``ArrayString`` by @despawnerer
- Add method ``try_extend_from_slice`` to ``ArrayVec``, which is always
effecient by @Thomasdezeeuw.
- Add method ``remaining_capacity`` by @Thomasdezeeuw
- Improve performance of the ``extend`` method.
- The index type of zero capacity vectors is now itself zero size, by
@clarfon
- Use ``drop_in_place`` for truncate and clear methods. This affects drop order
and resume from panic during drop.
- Use Rust 2018 edition for the implementation
- Require Rust 1.36 or later, for the unconditional ``MaybeUninit``
improvements.

@@ -31,0 +48,0 @@ - 0.4.11

@@ -5,17 +5,19 @@ use std::borrow::Borrow;

use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut};
use std::str;
use std::str::FromStr;
use std::str::Utf8Error;
use std::slice;
use array::{Array, ArrayExt};
use array::Index;
use CapacityError;
use char::encode_utf8;
use crate::array::Array;
use crate::array::Index;
use crate::CapacityError;
use crate::char::encode_utf8;
#[cfg(feature="serde-1")]
#[cfg(feature="serde")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
use super::MaybeUninit as MaybeUninitCopy;
/// A string with a fixed capacity.

@@ -29,9 +31,12 @@ ///

#[derive(Copy)]
pub struct ArrayString<A: Array<Item=u8>> {
// FIXME: Use Copyable union for xs when we can
xs: A,
pub struct ArrayString<A>
where A: Array<Item=u8> + Copy
{
xs: MaybeUninitCopy<A>,
len: A::Index,
}
impl<A: Array<Item=u8>> Default for ArrayString<A> {
impl<A> Default for ArrayString<A>
where A: Array<Item=u8> + Copy
{
/// Return an empty `ArrayString`

@@ -43,3 +48,5 @@ fn default() -> ArrayString<A> {

impl<A: Array<Item=u8>> ArrayString<A> {
impl<A> ArrayString<A>
where A: Array<Item=u8> + Copy
{
/// Create a new empty `ArrayString`.

@@ -60,4 +67,3 @@ ///

ArrayString {
// FIXME: Use Copyable union for xs when we can
xs: mem::zeroed(),
xs: MaybeUninitCopy::uninitialized(),
len: Index::from(0),

@@ -98,7 +104,8 @@ }

pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
let mut arraystr = Self::new();
let s = try!(str::from_utf8(b.as_slice()));
let _result = arraystr.try_push_str(s);
debug_assert!(_result.is_ok());
Ok(arraystr)
let len = str::from_utf8(b.as_slice())?.len();
debug_assert_eq!(len, A::CAPACITY);
Ok(ArrayString {
xs: MaybeUninitCopy::from(*b),
len: Index::from(A::CAPACITY),
})
}

@@ -115,3 +122,3 @@

#[inline]
pub fn capacity(&self) -> usize { A::capacity() }
pub fn capacity(&self) -> usize { A::CAPACITY }

@@ -222,3 +229,3 @@ /// Return if the `ArrayString` is completely filled.

unsafe {
let dst = self.xs.as_mut_ptr().offset(self.len() as isize);
let dst = self.xs.ptr_mut().offset(self.len() as isize);
let src = s.as_ptr();

@@ -317,4 +324,4 @@ ptr::copy_nonoverlapping(src, dst, s.len());

unsafe {
ptr::copy(self.xs.as_ptr().offset(next as isize),
self.xs.as_mut_ptr().offset(idx as isize),
ptr::copy(self.xs.ptr().offset(next as isize),
self.xs.ptr_mut().offset(idx as isize),
len - next);

@@ -353,7 +360,9 @@ self.set_len(len - (next - idx));

unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] {
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity())
slice::from_raw_parts_mut(self.xs.ptr_mut(), self.capacity())
}
}
impl<A: Array<Item=u8>> Deref for ArrayString<A> {
impl<A> Deref for ArrayString<A>
where A: Array<Item=u8> + Copy
{
type Target = str;

@@ -363,3 +372,3 @@ #[inline]

unsafe {
let sl = slice::from_raw_parts(self.xs.as_ptr(), self.len.to_usize());
let sl = slice::from_raw_parts(self.xs.ptr(), self.len.to_usize());
str::from_utf8_unchecked(sl)

@@ -370,9 +379,10 @@ }

impl<A: Array<Item=u8>> DerefMut for ArrayString<A> {
impl<A> DerefMut for ArrayString<A>
where A: Array<Item=u8> + Copy
{
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe {
let sl = slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.len.to_usize());
// FIXME: Nothing but transmute to do this right now
mem::transmute(sl)
let sl = slice::from_raw_parts_mut(self.xs.ptr_mut(), self.len.to_usize());
str::from_utf8_unchecked_mut(sl)
}

@@ -382,3 +392,5 @@ }

impl<A: Array<Item=u8>> PartialEq for ArrayString<A> {
impl<A> PartialEq for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &Self) -> bool {

@@ -389,3 +401,5 @@ **self == **rhs

impl<A: Array<Item=u8>> PartialEq<str> for ArrayString<A> {
impl<A> PartialEq<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &str) -> bool {

@@ -396,3 +410,5 @@ &**self == rhs

impl<A: Array<Item=u8>> PartialEq<ArrayString<A>> for str {
impl<A> PartialEq<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &ArrayString<A>) -> bool {

@@ -403,5 +419,9 @@ self == &**rhs

impl<A: Array<Item=u8>> Eq for ArrayString<A> { }
impl<A> Eq for ArrayString<A>
where A: Array<Item=u8> + Copy
{ }
impl<A: Array<Item=u8>> Hash for ArrayString<A> {
impl<A> Hash for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn hash<H: Hasher>(&self, h: &mut H) {

@@ -412,15 +432,23 @@ (**self).hash(h)

impl<A: Array<Item=u8>> Borrow<str> for ArrayString<A> {
impl<A> Borrow<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn borrow(&self) -> &str { self }
}
impl<A: Array<Item=u8>> AsRef<str> for ArrayString<A> {
impl<A> AsRef<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn as_ref(&self) -> &str { self }
}
impl<A: Array<Item=u8>> fmt::Debug for ArrayString<A> {
impl<A> fmt::Debug for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
}
impl<A: Array<Item=u8>> fmt::Display for ArrayString<A> {
impl<A> fmt::Display for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }

@@ -430,3 +458,5 @@ }

/// `Write` appends written data to the end of the string.
impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
impl<A> fmt::Write for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn write_char(&mut self, c: char) -> fmt::Result {

@@ -441,3 +471,5 @@ self.try_push(c).map_err(|_| fmt::Error)

impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
impl<A> Clone for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn clone(&self) -> ArrayString<A> {

@@ -453,3 +485,5 @@ *self

impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
impl<A> PartialOrd for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {

@@ -464,3 +498,5 @@ (**self).partial_cmp(&**rhs)

impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
impl<A> PartialOrd<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {

@@ -475,3 +511,5 @@ (**self).partial_cmp(rhs)

impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
impl<A> PartialOrd<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {

@@ -486,3 +524,5 @@ self.partial_cmp(&**rhs)

impl<A: Array<Item=u8>> Ord for ArrayString<A> {
impl<A> Ord for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn cmp(&self, rhs: &Self) -> cmp::Ordering {

@@ -493,5 +533,17 @@ (**self).cmp(&**rhs)

#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
impl<A> FromStr for ArrayString<A>
where A: Array<Item=u8> + Copy
{
type Err = CapacityError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from(s).map_err(CapacityError::simplify)
}
}
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
impl<A> Serialize for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

@@ -504,5 +556,7 @@ where S: Serializer

#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
impl<'de, A> Deserialize<'de> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>

@@ -516,7 +570,7 @@ where D: Deserializer<'de>

impl<'de, A: Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
impl<'de, A: Copy + Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
type Value = ArrayString<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string no more than {} bytes long", A::capacity())
write!(formatter, "a string no more than {} bytes long", A::CAPACITY)
}

@@ -533,3 +587,3 @@

{
let s = try!(str::from_utf8(v).map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self)));
let s = str::from_utf8(v).map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self))?;

@@ -536,0 +590,0 @@ ArrayString::from(s).map_err(|_| E::invalid_length(s.len(), &self))

@@ -15,14 +15,21 @@

/// (a few in this range are included by default).
///
/// ## Safety
///
/// This trait can *only* be implemented by fixed-size arrays or types with
/// *exactly* the representation of a fixed size array (of the right element
/// type and capacity).
///
/// Normally this trait is an implementation detail of arrayvec and doesn’t
/// need implementing.
pub unsafe trait Array {
/// The array’s element type
type Item;
/// The smallest type that can index and tell the length of the array.
#[doc(hidden)]
/// The smallest index type that indexes the array.
type Index: Index;
#[doc(hidden)]
fn as_ptr(&self) -> *const Self::Item;
#[doc(hidden)]
fn as_mut_ptr(&mut self) -> *mut Self::Item;
#[doc(hidden)]
fn capacity() -> usize;
/// The array's element capacity
const CAPACITY: usize;
fn as_slice(&self) -> &[Self::Item];
fn as_mut_slice(&mut self) -> &mut [Self::Item];
}

@@ -32,18 +39,19 @@

fn to_usize(self) -> usize;
fn from(usize) -> Self;
fn from(_: usize) -> Self;
}
use std::slice::{from_raw_parts};
impl Index for () {
#[inline(always)]
fn to_usize(self) -> usize { 0 }
#[inline(always)]
fn from(_ix: usize) -> Self { () }
}
pub trait ArrayExt : Array {
impl Index for bool {
#[inline(always)]
fn as_slice(&self) -> &[Self::Item] {
unsafe {
from_raw_parts(self.as_ptr(), Self::capacity())
}
}
fn to_usize(self) -> usize { self as usize }
#[inline(always)]
fn from(ix: usize) -> Self { ix != 0 }
}
impl<A> ArrayExt for A where A: Array { }
impl Index for u8 {

@@ -82,11 +90,9 @@ #[inline(always)]

type Index = $index_type;
const CAPACITY: usize = $len;
#[doc(hidden)]
#[inline(always)]
fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
#[inline]
fn as_slice(&self) -> &[Self::Item] { self }
#[doc(hidden)]
#[inline(always)]
fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
#[doc(hidden)]
#[inline(always)]
fn capacity() -> usize { $len }
#[inline]
fn as_mut_slice(&mut self) -> &mut [Self::Item] { self }
}

@@ -103,3 +109,6 @@ )

fix_array_impl_recursive!(u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
fix_array_impl_recursive!((), 0,);
fix_array_impl_recursive!(bool, 1,);
fix_array_impl_recursive!(u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,

@@ -106,0 +115,0 @@ 28, 29, 30, 31, );

+145
-77

@@ -10,5 +10,5 @@ //! **arrayvec** provides the types `ArrayVec` and `ArrayString`:

//!
//! - `serde-1`
//! - `serde`
//! - Optional
//! - Enable serialization for ArrayVec and ArrayString using serde 1.0
//! - Enable serialization for ArrayVec and ArrayString using serde 1.x
//! - `array-sizes-33-128`, `array-sizes-129-255`

@@ -20,9 +20,8 @@ //! - Optional

//!
//! This version of arrayvec requires Rust 1.13 or later.
//! This version of arrayvec requires Rust 1.36 or later.
//!
#![doc(html_root_url="https://docs.rs/arrayvec/0.4/")]
#![cfg_attr(not(feature="std"), no_std)]
#![cfg_attr(has_union_feature, feature(untagged_unions))]
#[cfg(feature="serde-1")]
#[cfg(feature="serde")]
extern crate serde;

@@ -33,13 +32,7 @@

#[cfg(not(has_manually_drop_in_union))]
extern crate nodrop;
use std::cmp;
use std::iter;
use std::mem;
use std::ops::{Bound, Deref, DerefMut, RangeBounds};
use std::ptr;
use std::ops::{
Deref,
DerefMut,
};
use std::slice;

@@ -56,14 +49,6 @@

#[cfg(has_stable_maybe_uninit)]
#[path="maybe_uninit_stable.rs"]
mod maybe_uninit;
#[cfg(all(not(has_stable_maybe_uninit), has_manually_drop_in_union))]
mod maybe_uninit;
#[cfg(all(not(has_stable_maybe_uninit), not(has_manually_drop_in_union)))]
#[path="maybe_uninit_nodrop.rs"]
mod maybe_uninit;
use crate::maybe_uninit::MaybeUninit;
use maybe_uninit::MaybeUninit;
#[cfg(feature="serde-1")]
#[cfg(feature="serde")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};

@@ -74,10 +59,8 @@

mod char;
mod range;
mod errors;
pub use array::Array;
pub use range::RangeArgument;
use array::Index;
pub use array_string::ArrayString;
pub use errors::CapacityError;
pub use crate::array::Array;
use crate::array::Index;
pub use crate::array_string::ArrayString;
pub use crate::errors::CapacityError;

@@ -160,3 +143,3 @@

#[inline]
pub fn capacity(&self) -> usize { A::capacity() }
pub fn capacity(&self) -> usize { A::CAPACITY }

@@ -175,2 +158,15 @@ /// Return if the `ArrayVec` is completely filled.

/// Returns the capacity left in the `ArrayVec`.
///
/// ```
/// use arrayvec::ArrayVec;
///
/// let mut array = ArrayVec::from([1, 2, 3]);
/// array.pop();
/// assert_eq!(array.remaining_capacity(), 1);
/// ```
pub fn remaining_capacity(&self) -> usize {
self.capacity() - self.len()
}
/// Push `element` to the end of the vector.

@@ -217,3 +213,3 @@ ///

pub fn try_push(&mut self, element: A::Item) -> Result<(), CapacityError<A::Item>> {
if self.len() < A::capacity() {
if self.len() < A::CAPACITY {
unsafe {

@@ -253,12 +249,7 @@ self.push_unchecked(element);

let len = self.len();
debug_assert!(len < A::capacity());
ptr::write(self.get_unchecked_ptr(len), element);
debug_assert!(len < A::CAPACITY);
ptr::write(self.get_unchecked_mut(len), element);
self.set_len(len + 1);
}
/// Get pointer to where element at `index` would be
unsafe fn get_unchecked_ptr(&mut self, index: usize) -> *mut A::Item {
self.xs.ptr_mut().offset(index as isize)
}
/// Insert `element` at position `index`.

@@ -321,3 +312,3 @@ ///

{
let p: *mut _ = self.get_unchecked_ptr(index);
let p: *mut _ = self.get_unchecked_mut(index);
// Shift everything over to make space. (Duplicating the

@@ -351,3 +342,3 @@ // `index`th element into two consecutive places.)

if self.len() == 0 {
return None
return None;
}

@@ -357,3 +348,3 @@ unsafe {

self.set_len(new_len);
Some(ptr::read(self.get_unchecked_ptr(new_len)))
Some(ptr::read(self.get_unchecked_mut(new_len)))
}

@@ -475,4 +466,10 @@ }

/// ```
pub fn truncate(&mut self, len: usize) {
while self.len() > len { self.pop(); }
pub fn truncate(&mut self, new_len: usize) {
unsafe {
if new_len < self.len() {
let tail: *mut [_] = &mut self[new_len..];
self.len = Index::from(new_len);
ptr::drop_in_place(tail);
}
}
}

@@ -482,3 +479,3 @@

pub fn clear(&mut self) {
while let Some(_) = self.pop() { }
self.truncate(0)
}

@@ -525,3 +522,3 @@

///
/// This method uses *debug assertions* to check that check that `length` is
/// This method uses *debug assertions* to check that `length` is
/// not greater than the capacity.

@@ -534,2 +531,38 @@ #[inline]

/// Copy and appends all elements in a slice to the `ArrayVec`.
///
/// ```
/// use arrayvec::ArrayVec;
///
/// let mut vec: ArrayVec<[usize; 10]> = ArrayVec::new();
/// vec.push(1);
/// vec.try_extend_from_slice(&[2, 3]).unwrap();
/// assert_eq!(&vec[..], &[1, 2, 3]);
/// ```
///
/// # Errors
///
/// This method will return an error if the capacity left (see
/// [`remaining_capacity`]) is smaller then the length of the provided
/// slice.
///
/// [`remaining_capacity`]: #method.remaining_capacity
pub fn try_extend_from_slice(&mut self, other: &[A::Item]) -> Result<(), CapacityError>
where A::Item: Copy,
{
if self.remaining_capacity() < other.len() {
return Err(CapacityError::new(()));
}
let self_len = self.len();
let other_len = other.len();
unsafe {
let dst = self.xs.ptr_mut().offset(self_len as isize);
ptr::copy_nonoverlapping(other.as_ptr(), dst, other_len);
self.set_len(self_len + other_len);
}
Ok(())
}
/// Create a draining iterator that removes the specified range in the vector

@@ -553,7 +586,9 @@ /// and yields the removed items from start to end. The element range is

/// ```
pub fn drain<R: RangeArgument>(&mut self, range: R) -> Drain<A> {
pub fn drain<R>(&mut self, range: R) -> Drain<A>
where R: RangeBounds<usize>
{
// Memory safety
//
// When the Drain is first created, it shortens the length of
// the source vector to make sure no uninitalized or moved-from elements
// the source vector to make sure no uninitialized or moved-from elements
// are accessible at all if the Drain's destructor never gets to run.

@@ -566,4 +601,18 @@ //

let len = self.len();
let start = range.start().unwrap_or(0);
let end = range.end().unwrap_or(len);
let start = match range.start_bound() {
Bound::Unbounded => 0,
Bound::Included(&i) => i,
Bound::Excluded(&i) => i.saturating_add(1),
};
let end = match range.end_bound() {
Bound::Excluded(&j) => j,
Bound::Included(&j) => j.saturating_add(1),
Bound::Unbounded => len,
};
self.drain_range(start, end)
}
fn drain_range(&mut self, start: usize, end: usize) -> Drain<A>
{
let len = self.len();
// bounds check happens here

@@ -588,5 +637,2 @@ let range_slice: *const _ = &self[start..end];

/// return an `Err` with self otherwise.
///
/// `Note:` This function may incur unproportionally large overhead
/// to move the array out, its performance is not optimal.
pub fn into_inner(self) -> Result<A, Self> {

@@ -652,3 +698,3 @@ if self.len() < self.capacity() {

fn from(array: A) -> Self {
ArrayVec { xs: MaybeUninit::from(array), len: Index::from(A::capacity()) }
ArrayVec { xs: MaybeUninit::from(array), len: Index::from(A::CAPACITY) }
}

@@ -729,3 +775,3 @@ }

self.index = Index::from(index + 1);
Some(ptr::read(self.v.get_unchecked_ptr(index)))
Some(ptr::read(self.v.get_unchecked_mut(index)))
}

@@ -750,3 +796,3 @@ }

self.v.set_len(new_len);
Some(ptr::read(self.v.get_unchecked_ptr(new_len)))
Some(ptr::read(self.v.get_unchecked_mut(new_len)))
}

@@ -767,3 +813,3 @@ }

let elements = slice::from_raw_parts_mut(
self.v.get_unchecked_ptr(index),
self.v.get_unchecked_mut(index),
len - index);

@@ -902,3 +948,4 @@ ptr::drop_in_place(elements);

let len = self.len();
let mut ptr = self.as_mut_ptr().offset(len as isize);
let mut ptr = raw_ptr_add(self.as_mut_ptr(), len);
let end_ptr = raw_ptr_add(ptr, take);
// Keep the length in a separate variable, write it back on scope

@@ -909,12 +956,18 @@ // exit. To help the compiler with alias analysis and stuff.

let mut guard = ScopeExitGuard {
value: self,
value: &mut self.len,
data: len,
f: |&len, self_| {
self_.set_len(len)
f: move |&len, self_len| {
**self_len = Index::from(len);
}
};
for elt in iter.into_iter().take(take) {
ptr::write(ptr, elt);
ptr = ptr.offset(1);
guard.data += 1;
let mut iter = iter.into_iter();
loop {
if ptr == end_ptr { break; }
if let Some(elt) = iter.next() {
raw_ptr_write(ptr, elt);
ptr = raw_ptr_add(ptr, 1);
guard.data += 1;
} else {
break;
}
}

@@ -925,2 +978,20 @@ }

/// Rawptr add but uses arithmetic distance for ZST
unsafe fn raw_ptr_add<T>(ptr: *mut T, offset: usize) -> *mut T {
if mem::size_of::<T>() == 0 {
// Special case for ZST
(ptr as usize).wrapping_add(offset) as _
} else {
ptr.offset(offset as isize)
}
}
unsafe fn raw_ptr_write<T>(ptr: *mut T, value: T) {
if mem::size_of::<T>() == 0 {
/* nothing */
} else {
ptr::write(ptr, value)
}
}
/// Create an `ArrayVec` from an iterator.

@@ -1054,9 +1125,6 @@ ///

fn write(&mut self, data: &[u8]) -> io::Result<usize> {
unsafe {
let len = self.len();
let write_len = cmp::min(A::capacity() - len, data.len());
ptr::copy_nonoverlapping(data.as_ptr(), self.get_unchecked_ptr(len), write_len);
self.set_len(len + write_len);
Ok(write_len)
}
let len = cmp::min(self.remaining_capacity(), data.len());
let _result = self.try_extend_from_slice(&data[..len]);
debug_assert!(_result.is_ok());
Ok(len)
}

@@ -1066,4 +1134,4 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }

#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
impl<T: Serialize, A: Array<Item=T>> Serialize for ArrayVec<A> {

@@ -1077,4 +1145,4 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
impl<'de, T: Deserialize<'de>, A: Array<Item=T>> Deserialize<'de> for ArrayVec<A> {

@@ -1093,3 +1161,3 @@ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "an array with no more than {} items", A::capacity())
write!(formatter, "an array with no more than {} items", A::CAPACITY)
}

@@ -1102,5 +1170,5 @@

while let Some(value) = try!(seq.next_element()) {
while let Some(value) = seq.next_element()? {
if let Err(_) = values.try_push(value) {
return Err(SA::Error::invalid_length(A::capacity() + 1, &self));
return Err(SA::Error::invalid_length(A::CAPACITY + 1, &self));
}

@@ -1107,0 +1175,0 @@ }

use array::Array;
use std::mem::ManuallyDrop;
use crate::array::Array;
use std::mem::MaybeUninit as StdMaybeUninit;
/// A combination of ManuallyDrop and “maybe uninitialized”;
/// this wraps a value that can be wholly or partially uninitialized;
/// it also has no drop regardless of the type of T.
#[repr(C)] // for cast from self ptr to value
pub union MaybeUninit<T> {
empty: (),
value: ManuallyDrop<T>,
#[derive(Copy)]
pub struct MaybeUninit<T> {
inner: StdMaybeUninit<T>,
}
// Why we don't use std's MaybeUninit on nightly? See the ptr method
impl<T> Clone for MaybeUninit<T>
where T: Copy
{
fn clone(&self) -> Self { *self }
}
impl<T> MaybeUninit<T> {
/// Create a new MaybeUninit with uninitialized interior
pub unsafe fn uninitialized() -> Self {
MaybeUninit { empty: () }
MaybeUninit { inner: StdMaybeUninit::uninit() }
}

@@ -24,3 +25,3 @@

pub fn from(v: T) -> Self {
MaybeUninit { value: ManuallyDrop::new(v) }
MaybeUninit { inner: StdMaybeUninit::new(v) }
}

@@ -35,6 +36,3 @@

{
// std MaybeUninit creates a &self.value reference here which is
// not guaranteed to be sound in our case - we will partially
// initialize the value, not always wholly.
self as *const _ as *const T::Item
self.inner.as_ptr() as *const T::Item
}

@@ -46,4 +44,4 @@

{
self as *mut _ as *mut T::Item
self.inner.as_mut_ptr() as *mut T::Item
}
}

@@ -1,2 +0,2 @@

#![cfg(feature = "serde-1")]
#![cfg(feature = "serde")]
extern crate arrayvec;

@@ -3,0 +3,0 @@ extern crate serde_test;

@@ -31,2 +31,40 @@ extern crate arrayvec;

#[test]
fn test_capacity_left() {
let mut vec: ArrayVec<[usize; 4]> = ArrayVec::new();
assert_eq!(vec.remaining_capacity(), 4);
vec.push(1);
assert_eq!(vec.remaining_capacity(), 3);
vec.push(2);
assert_eq!(vec.remaining_capacity(), 2);
vec.push(3);
assert_eq!(vec.remaining_capacity(), 1);
vec.push(4);
assert_eq!(vec.remaining_capacity(), 0);
}
#[test]
fn test_extend_from_slice() {
let mut vec: ArrayVec<[usize; 10]> = ArrayVec::new();
vec.try_extend_from_slice(&[1, 2, 3]).unwrap();
assert_eq!(vec.len(), 3);
assert_eq!(&vec[..], &[1, 2, 3]);
assert_eq!(vec.pop(), Some(3));
assert_eq!(&vec[..], &[1, 2]);
}
#[test]
fn test_extend_from_slice_error() {
let mut vec: ArrayVec<[usize; 10]> = ArrayVec::new();
vec.try_extend_from_slice(&[1, 2, 3]).unwrap();
let res = vec.try_extend_from_slice(&[0; 8]);
assert_matches!(res, Err(_));
let mut vec: ArrayVec<[usize; 0]> = ArrayVec::new();
let res = vec.try_extend_from_slice(&[0; 1]);
assert_matches!(res, Err(_));
}
#[test]
fn test_u16_index() {

@@ -131,2 +169,76 @@ const N: usize = 4096;

#[test]
fn test_drop_panics() {
use std::cell::Cell;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;
let flag = &Cell::new(0);
struct Bump<'a>(&'a Cell<i32>);
// Panic in the first drop
impl<'a> Drop for Bump<'a> {
fn drop(&mut self) {
let n = self.0.get();
self.0.set(n + 1);
if n == 0 {
panic!("Panic in Bump's drop");
}
}
}
// check if rust is new enough
flag.set(0);
{
let array = vec![Bump(flag), Bump(flag)];
let res = catch_unwind(AssertUnwindSafe(|| {
drop(array);
}));
assert!(res.is_err());
}
if flag.get() != 2 {
println!("test_drop_panics: skip, this version of Rust doesn't continue in drop_in_place");
return;
}
flag.set(0);
{
let mut array = ArrayVec::<[Bump; 128]>::new();
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
let res = catch_unwind(AssertUnwindSafe(|| {
drop(array);
}));
assert!(res.is_err());
}
// Check that all the elements drop, even if the first drop panics.
assert_eq!(flag.get(), 3);
flag.set(0);
{
let mut array = ArrayVec::<[Bump; 16]>::new();
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
let i = 2;
let tail_len = array.len() - i;
let res = catch_unwind(AssertUnwindSafe(|| {
array.truncate(i);
}));
assert!(res.is_err());
// Check that all the tail elements drop, even if the first drop panics.
assert_eq!(flag.get(), tail_len as i32);
}
}
#[test]
fn test_extend() {

@@ -151,4 +263,4 @@ let mut range = 0..10;

let data = ArrayVec::<[Vec<i32>; 5]>::new();
&data as &Send;
&data as &Sync;
&data as &dyn Send;
&data as &dyn Sync;
}

@@ -164,2 +276,7 @@

// 1 enum tag + 1 drop flag
type EmptyArray = ArrayVec<[u8; 0]>;
println!("{}", mem::size_of::<EmptyArray>());
assert!(mem::size_of::<EmptyArray>() <= 2);
// 12 element size + 1 enum tag + 3 padding + 1 len + 1 drop flag + 2 padding

@@ -197,2 +314,25 @@ type QuadArray = ArrayVec<[u32; 3]>;

#[test]
fn test_drain_range_inclusive() {
let mut v = ArrayVec::from([0; 8]);
v.drain(0..=7);
assert_eq!(&v[..], &[]);
v.extend(0..);
v.drain(1..=4);
assert_eq!(&v[..], &[0, 5, 6, 7]);
let u: ArrayVec<[_; 3]> = v.drain(1..=2).rev().collect();
assert_eq!(&u[..], &[6, 5]);
assert_eq!(&v[..], &[0, 7]);
v.drain(..);
assert_eq!(&v[..], &[]);
}
#[test]
#[should_panic]
fn test_drain_range_inclusive_oob() {
let mut v = ArrayVec::from([0; 0]);
v.drain(0..=0);
}
#[test]
fn test_retain() {

@@ -302,2 +442,3 @@ let mut v = ArrayVec::from([0; 8]);

#[cfg(feature="std")]
#[test]

@@ -337,2 +478,3 @@ fn test_write() {

#[cfg(feature="std")]
#[test]

@@ -363,5 +505,5 @@ fn test_string() {

// Test Error trait / try
let t = || -> Result<(), Box<Error>> {
let t = || -> Result<(), Box<dyn Error>> {
let mut t = ArrayString::<[_; 2]>::new();
try!(t.try_push_str(text));
t.try_push_str(text)?;
Ok(())

@@ -382,2 +524,10 @@ }();

#[test]
fn test_string_parse_from_str() {
let text = "hello world";
let u: ArrayString<[_; 11]> = text.parse().unwrap();
assert_eq!(&u, text);
assert_eq!(u.len(), text.len());
}
#[test]
fn test_string_from_bytes() {

@@ -520,8 +670,20 @@ let text = "hello world";

#[test]
fn test_extend_zst() {
let mut range = 0..10;
#[derive(Copy, Clone, PartialEq, Debug)]
struct Z; // Zero sized type
#[test]
fn test_newish_stable_uses_maybe_uninit() {
if option_env!("ARRAYVECTEST_ENSURE_MAYBEUNINIT").map(|s| !s.is_empty()).unwrap_or(false) {
assert!(cfg!(has_stable_maybe_uninit));
}
let mut array: ArrayVec<[_; 5]> = range.by_ref().map(|_| Z).collect();
assert_eq!(&array[..], &[Z; 5]);
assert_eq!(range.next(), Some(5));
array.extend(range.by_ref().map(|_| Z));
assert_eq!(range.next(), Some(6));
let mut array: ArrayVec<[_; 10]> = (0..3).map(|_| Z).collect();
assert_eq!(&array[..], &[Z; 3]);
array.extend((3..5).map(|_| Z));
assert_eq!(&array[..], &[Z; 5]);
assert_eq!(array.len(), 5);
}
use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
fn main() {
// we need to output *some* file to opt out of the default
println!("cargo:rerun-if-changed=build.rs");
detect_maybe_uninit();
}
fn detect_maybe_uninit() {
let has_stable_maybe_uninit = probe(&stable_maybe_uninit());
if has_stable_maybe_uninit {
println!("cargo:rustc-cfg=has_stable_maybe_uninit");
return;
}
let has_unstable_union_with_md = probe(&maybe_uninit_code(true));
if has_unstable_union_with_md {
println!("cargo:rustc-cfg=has_manually_drop_in_union");
println!("cargo:rustc-cfg=has_union_feature");
}
}
// To guard against changes in this currently unstable feature, use
// a detection tests instead of a Rustc version and/or date test.
fn stable_maybe_uninit() -> String {
let code = "
#![allow(warnings)]
use std::mem::MaybeUninit;
fn main() { }
";
code.to_string()
}
// To guard against changes in this currently unstable feature, use
// a detection tests instead of a Rustc version and/or date test.
fn maybe_uninit_code(use_feature: bool) -> String {
let feature = if use_feature { "#![feature(untagged_unions)]" } else { "" };
let code = "
#![allow(warnings)]
use std::mem::ManuallyDrop;
#[derive(Copy)]
pub union MaybeUninit<T> {
empty: (),
value: ManuallyDrop<T>,
}
impl<T> Clone for MaybeUninit<T> where T: Copy
{
fn clone(&self) -> Self { *self }
}
fn main() {
let value1 = MaybeUninit::<[i32; 3]> { empty: () };
let value2 = MaybeUninit { value: ManuallyDrop::new([1, 2, 3]) };
}
";
[feature, code].concat()
}
/// Test if a code snippet can be compiled
fn probe(code: &str) -> bool {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR");
let mut child = Command::new(rustc)
.arg("--out-dir")
.arg(out_dir)
.arg("--emit=obj")
.arg("-")
.stdin(Stdio::piped())
.spawn()
.expect("rustc probe");
child
.stdin
.as_mut()
.expect("rustc stdin")
.write_all(code.as_bytes())
.expect("write rustc stdin");
child.wait().expect("rustc probe").success()
}
use array::Array;
use nodrop::NoDrop;
use std::mem::uninitialized;
/// A combination of NoDrop and “maybe uninitialized”;
/// this wraps a value that can be wholly or partially uninitialized.
///
/// NOTE: This is known to not be a good solution, but it's the one we have kept
/// working on stable Rust. Stable improvements are encouraged, in any form,
/// but of course we are waiting for a real, stable, MaybeUninit.
pub struct MaybeUninit<T>(NoDrop<T>);
// why don't we use ManuallyDrop here: It doesn't inhibit
// enum layout optimizations that depend on T, and we support older Rust.
impl<T> MaybeUninit<T> {
/// Create a new MaybeUninit with uninitialized interior
pub unsafe fn uninitialized() -> Self {
Self::from(uninitialized())
}
/// Create a new MaybeUninit from the value `v`.
pub fn from(v: T) -> Self {
MaybeUninit(NoDrop::new(v))
}
/// Return a raw pointer to the start of the interior array
pub fn ptr(&self) -> *const T::Item
where T: Array
{
&*self.0 as *const T as *const _
}
/// Return a mut raw pointer to the start of the interior array
pub fn ptr_mut(&mut self) -> *mut T::Item
where T: Array
{
&mut *self.0 as *mut T as *mut _
}
}
use array::Array;
use std::mem::MaybeUninit as StdMaybeUninit;
pub struct MaybeUninit<T> {
inner: StdMaybeUninit<T>,
}
impl<T> MaybeUninit<T> {
/// Create a new MaybeUninit with uninitialized interior
pub unsafe fn uninitialized() -> Self {
MaybeUninit { inner: StdMaybeUninit::uninit() }
}
/// Create a new MaybeUninit from the value `v`.
pub fn from(v: T) -> Self {
MaybeUninit { inner: StdMaybeUninit::new(v) }
}
// Raw pointer casts written so that we don't reference or access the
// uninitialized interior value
/// Return a raw pointer to the start of the interior array
pub fn ptr(&self) -> *const T::Item
where T: Array
{
// std MaybeUninit creates a &self.value reference here which is
// not guaranteed to be sound in our case - we will partially
// initialize the value, not always wholly.
self.inner.as_ptr() as *const T::Item
}
/// Return a mut raw pointer to the start of the interior array
pub fn ptr_mut(&mut self) -> *mut T::Item
where T: Array
{
self.inner.as_mut_ptr() as *mut T::Item
}
}
use std::ops::{
RangeFull,
RangeFrom,
RangeTo,
Range,
};
/// `RangeArgument` is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
///
/// Note: This is arrayvec's provisional trait, waiting for stable Rust to
/// provide an equivalent.
pub trait RangeArgument {
#[inline]
/// Start index (inclusive)
fn start(&self) -> Option<usize> { None }
#[inline]
/// End index (exclusive)
fn end(&self) -> Option<usize> { None }
}
impl RangeArgument for RangeFull {}
impl RangeArgument for RangeFrom<usize> {
#[inline]
fn start(&self) -> Option<usize> { Some(self.start) }
}
impl RangeArgument for RangeTo<usize> {
#[inline]
fn end(&self) -> Option<usize> { Some(self.end) }
}
impl RangeArgument for Range<usize> {
#[inline]
fn start(&self) -> Option<usize> { Some(self.start) }
#[inline]
fn end(&self) -> Option<usize> { Some(self.end) }
}

Sorry, the diff of this file is not supported yet