diff -Nru rust-arrayvec-0.4.11/benches/extend.rs rust-arrayvec-0.5.1/benches/extend.rs --- rust-arrayvec-0.4.11/benches/extend.rs 2019-07-10 14:39:09.000000000 +0000 +++ rust-arrayvec-0.5.1/benches/extend.rs 2019-10-09 14:32:55.000000000 +0000 @@ -2,17 +2,21 @@ extern crate arrayvec; #[macro_use] extern crate bencher; +use std::io::Write; + use arrayvec::ArrayVec; use bencher::Bencher; +use bencher::black_box; fn extend_with_constant(b: &mut Bencher) { let mut v = ArrayVec::<[u8; 512]>::new(); let cap = v.capacity(); b.iter(|| { v.clear(); - v.extend((0..cap).map(|_| 1)); - v[0] + let constant = black_box(1); + v.extend((0..cap).map(move |_| constant)); + v[511] }); b.bytes = v.capacity() as u64; } @@ -22,8 +26,9 @@ let cap = v.capacity(); b.iter(|| { 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] }); b.bytes = v.capacity() as u64; } @@ -33,11 +38,41 @@ let data = [1; 512]; b.iter(|| { v.clear(); - v.extend(data.iter().cloned()); - v[0] + let iter = data.iter().map(|&x| x); + v.extend(iter); + v[511] + }); + b.bytes = v.capacity() as u64; +} + +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; } -benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice); +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); diff -Nru rust-arrayvec-0.4.11/build.rs rust-arrayvec-0.5.1/build.rs --- rust-arrayvec-0.4.11/build.rs 2019-07-10 15:23:29.000000000 +0000 +++ rust-arrayvec-0.5.1/build.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ - -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 { - empty: (), - value: ManuallyDrop, - } - - impl Clone for MaybeUninit 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() -} diff -Nru rust-arrayvec-0.4.11/Cargo.toml rust-arrayvec-0.5.1/Cargo.toml --- rust-arrayvec-0.4.11/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rust-arrayvec-0.5.1/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -11,8 +11,9 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "arrayvec" -version = "0.4.11" +version = "0.5.1" authors = ["bluss"] description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString." documentation = "https://docs.rs/arrayvec/" @@ -21,10 +22,16 @@ license = "MIT/Apache-2.0" repository = "https://github.com/bluss/arrayvec" [package.metadata.docs.rs] -features = ["serde-1"] +features = ["serde"] [package.metadata.release] no-dev-version = true +tag-name = "{{version}}" +[profile.bench] +debug = true + +[profile.release] +debug = true [[bench]] name = "extend" @@ -33,10 +40,6 @@ [[bench]] name = "arraystring" harness = false -[dependencies.nodrop] -version = "0.1.12" -default-features = false - [dependencies.serde] version = "1.0" optional = true @@ -56,6 +59,4 @@ array-sizes-129-255 = [] array-sizes-33-128 = [] default = ["std"] -serde-1 = ["serde"] std = [] -use_union = [] diff -Nru rust-arrayvec-0.4.11/Cargo.toml.orig rust-arrayvec-0.5.1/Cargo.toml.orig --- rust-arrayvec-0.4.11/Cargo.toml.orig 2019-07-10 15:24:16.000000000 +0000 +++ rust-arrayvec-0.5.1/Cargo.toml.orig 2019-10-09 14:38:50.000000000 +0000 @@ -1,8 +1,9 @@ [package] name = "arrayvec" -version = "0.4.11" +version = "0.5.1" authors = ["bluss"] license = "MIT/Apache-2.0" +edition = "2018" description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString." documentation = "https://docs.rs/arrayvec/" @@ -13,9 +14,6 @@ [build-dependencies] -[dependencies] -nodrop = { version = "0.1.12", path = "nodrop", default-features = false } - [dependencies.serde] version = "1.0" optional = true @@ -39,16 +37,18 @@ [features] default = ["std"] std = [] -serde-1 = ["serde"] array-sizes-33-128 = [] array-sizes-129-255 = [] -# has no effect -use_union = [] +[profile.bench] +debug = true +[profile.release] +debug = true [package.metadata.docs.rs] -features = ["serde-1"] +features = ["serde"] [package.metadata.release] no-dev-version = true +tag-name = "{{version}}" diff -Nru rust-arrayvec-0.4.11/.cargo_vcs_info.json rust-arrayvec-0.5.1/.cargo_vcs_info.json --- rust-arrayvec-0.4.11/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 +++ rust-arrayvec-0.5.1/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +1,5 @@ { "git": { - "sha1": "97925027920f7a284774f76a48c3126297d2fd13" + "sha1": "6905bdbb8a873c3e5c965833b56e494b26b1c816" } } diff -Nru rust-arrayvec-0.4.11/debian/cargo-checksum.json rust-arrayvec-0.5.1/debian/cargo-checksum.json --- rust-arrayvec-0.4.11/debian/cargo-checksum.json 2019-07-11 09:52:58.000000000 +0000 +++ rust-arrayvec-0.5.1/debian/cargo-checksum.json 2019-12-28 10:55:58.000000000 +0000 @@ -1 +1 @@ -{"package":"Could not get crate checksum","files":{}} +{"package":"cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8","files":{}} diff -Nru rust-arrayvec-0.4.11/debian/changelog rust-arrayvec-0.5.1/debian/changelog --- rust-arrayvec-0.4.11/debian/changelog 2019-07-11 09:52:58.000000000 +0000 +++ rust-arrayvec-0.5.1/debian/changelog 2019-12-28 10:55:58.000000000 +0000 @@ -1,3 +1,9 @@ +rust-arrayvec (0.5.1-1) unstable; urgency=medium + + * Package arrayvec 0.5.1 from crates.io using debcargo 2.4.0 + + -- Andrej Shadura Sat, 28 Dec 2019 11:55:58 +0100 + rust-arrayvec (0.4.11-1) unstable; urgency=medium * Package arrayvec 0.4.11 from crates.io using debcargo 2.3.1-alpha.0 diff -Nru rust-arrayvec-0.4.11/debian/control rust-arrayvec-0.5.1/debian/control --- rust-arrayvec-0.4.11/debian/control 2019-07-11 09:52:58.000000000 +0000 +++ rust-arrayvec-0.5.1/debian/control 2019-12-28 10:55:58.000000000 +0000 @@ -5,8 +5,7 @@ dh-cargo (>= 18), cargo:native , rustc:native , - libstd-rust-dev , - librust-nodrop-0.1-dev (>= 0.1.12-~~) + libstd-rust-dev Maintainer: Debian Rust Maintainers Uploaders: Wolfgang Silbermayr , @@ -19,8 +18,7 @@ Architecture: any Multi-Arch: same Depends: - ${misc:Depends}, - librust-nodrop-0.1-dev (>= 0.1.12-~~) + ${misc:Depends} Suggests: librust-arrayvec+serde-dev (= ${binary:Version}) Provides: @@ -28,25 +26,21 @@ librust-arrayvec+array-sizes-33-128-dev (= ${binary:Version}), librust-arrayvec+default-dev (= ${binary:Version}), librust-arrayvec+std-dev (= ${binary:Version}), - librust-arrayvec+use-union-dev (= ${binary:Version}), librust-arrayvec-0-dev (= ${binary:Version}), librust-arrayvec-0+array-sizes-129-255-dev (= ${binary:Version}), librust-arrayvec-0+array-sizes-33-128-dev (= ${binary:Version}), librust-arrayvec-0+default-dev (= ${binary:Version}), librust-arrayvec-0+std-dev (= ${binary:Version}), - librust-arrayvec-0+use-union-dev (= ${binary:Version}), - librust-arrayvec-0.4-dev (= ${binary:Version}), - librust-arrayvec-0.4+array-sizes-129-255-dev (= ${binary:Version}), - librust-arrayvec-0.4+array-sizes-33-128-dev (= ${binary:Version}), - librust-arrayvec-0.4+default-dev (= ${binary:Version}), - librust-arrayvec-0.4+std-dev (= ${binary:Version}), - librust-arrayvec-0.4+use-union-dev (= ${binary:Version}), - librust-arrayvec-0.4.11-dev (= ${binary:Version}), - librust-arrayvec-0.4.11+array-sizes-129-255-dev (= ${binary:Version}), - librust-arrayvec-0.4.11+array-sizes-33-128-dev (= ${binary:Version}), - librust-arrayvec-0.4.11+default-dev (= ${binary:Version}), - librust-arrayvec-0.4.11+std-dev (= ${binary:Version}), - librust-arrayvec-0.4.11+use-union-dev (= ${binary:Version}) + librust-arrayvec-0.5-dev (= ${binary:Version}), + librust-arrayvec-0.5+array-sizes-129-255-dev (= ${binary:Version}), + librust-arrayvec-0.5+array-sizes-33-128-dev (= ${binary:Version}), + librust-arrayvec-0.5+default-dev (= ${binary:Version}), + librust-arrayvec-0.5+std-dev (= ${binary:Version}), + librust-arrayvec-0.5.1-dev (= ${binary:Version}), + librust-arrayvec-0.5.1+array-sizes-129-255-dev (= ${binary:Version}), + librust-arrayvec-0.5.1+array-sizes-33-128-dev (= ${binary:Version}), + librust-arrayvec-0.5.1+default-dev (= ${binary:Version}), + librust-arrayvec-0.5.1+std-dev (= ${binary:Version}) Description: Vector with fixed capacity, backed by an array - Rust source code Implements fixed capacity ArrayVec and ArrayString. . @@ -61,17 +55,11 @@ librust-arrayvec-dev (= ${binary:Version}), librust-serde-1-dev Provides: - librust-arrayvec+serde-1-dev (= ${binary:Version}), librust-arrayvec-0+serde-dev (= ${binary:Version}), - librust-arrayvec-0+serde-1-dev (= ${binary:Version}), - librust-arrayvec-0.4+serde-dev (= ${binary:Version}), - librust-arrayvec-0.4+serde-1-dev (= ${binary:Version}), - librust-arrayvec-0.4.11+serde-dev (= ${binary:Version}), - librust-arrayvec-0.4.11+serde-1-dev (= ${binary:Version}) -Description: Vector with fixed capacity, backed by an array - feature "serde" and 1 more + librust-arrayvec-0.5+serde-dev (= ${binary:Version}), + librust-arrayvec-0.5.1+serde-dev (= ${binary:Version}) +Description: Vector with fixed capacity, backed by an array - feature "serde" Implements fixed capacity ArrayVec and ArrayString. . This metapackage enables feature "serde" for the Rust arrayvec crate, by pulling in any additional dependencies needed by that feature. - . - Additionally, this package also provides the "serde-1" feature. diff -Nru rust-arrayvec-0.4.11/debian/tests/control rust-arrayvec-0.5.1/debian/tests/control --- rust-arrayvec-0.4.11/debian/tests/control 2019-07-11 09:52:58.000000000 +0000 +++ rust-arrayvec-0.5.1/debian/tests/control 2019-12-28 10:55:58.000000000 +0000 @@ -1,11 +1,11 @@ -Test-Command: /usr/share/cargo/bin/cargo-auto-test arrayvec 0.4.11 --all-targets --all-features +Test-Command: /usr/share/cargo/bin/cargo-auto-test arrayvec 0.5.1 --all-targets --all-features Depends: dh-cargo (>= 18), librust-bencher-0.1+default-dev (>= 0.1.4-~~), librust-matches-0.1+default-dev, librust-serde-test-1+default-dev, @ Restrictions: allow-stderr, skip-not-installable -Test-Command: /usr/share/cargo/bin/cargo-auto-test arrayvec 0.4.11 --all-targets --no-default-features +Test-Command: /usr/share/cargo/bin/cargo-auto-test arrayvec 0.5.1 --all-targets --no-default-features Depends: dh-cargo (>= 18), librust-bencher-0.1+default-dev (>= 0.1.4-~~), librust-matches-0.1+default-dev, librust-serde-test-1+default-dev, librust-arrayvec-dev Restrictions: allow-stderr, skip-not-installable -Test-Command: /usr/share/cargo/bin/cargo-auto-test arrayvec 0.4.11 --all-targets --features serde +Test-Command: /usr/share/cargo/bin/cargo-auto-test arrayvec 0.5.1 --all-targets --features serde Depends: dh-cargo (>= 18), librust-bencher-0.1+default-dev (>= 0.1.4-~~), librust-matches-0.1+default-dev, librust-serde-test-1+default-dev, librust-arrayvec+serde-dev Restrictions: allow-stderr, skip-not-installable diff -Nru rust-arrayvec-0.4.11/.gitignore rust-arrayvec-0.5.1/.gitignore --- rust-arrayvec-0.4.11/.gitignore 2018-11-28 14:58:48.000000000 +0000 +++ rust-arrayvec-0.5.1/.gitignore 2019-10-09 14:32:55.000000000 +0000 @@ -9,4 +9,4 @@ # Generated by Cargo /Cargo.lock -/target/ +/target diff -Nru rust-arrayvec-0.4.11/README.rst rust-arrayvec-0.5.1/README.rst --- rust-arrayvec-0.4.11/README.rst 2019-07-10 15:23:16.000000000 +0000 +++ rust-arrayvec-0.5.1/README.rst 2019-10-09 14:40:25.000000000 +0000 @@ -22,6 +22,46 @@ Recent Changes (arrayvec) ------------------------- +- 0.5.1 + + - Add ``as_ptr``, ``as_mut_ptr`` accessors directly on the ``ArrayVec`` by @tbu- + (matches the same addition to ``Vec`` which happened in Rust 1.37). + - Add method ``ArrayString::len`` (now available directly, not just through deref to str). + - Use raw pointers instead of ``&mut [u8]`` for encoding chars into ``ArrayString`` + (uninit best practice fix). + - Use raw pointers instead of ``get_unchecked_mut`` where the target may be + uninitialized a everywhere relevant in the ArrayVec implementation + (uninit best practice fix). + - Changed inline hints on many methods, mainly removing inline hints + - ``ArrayVec::dispose`` is now deprecated (it has no purpose anymore) + +- 0.4.12 + + - Use raw pointers instead of ``get_unchecked_mut`` where the target may be + uninitialized a everywhere relevant in the ArrayVec implementation. + +- 0.5.0 + + - 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. + - 0.4.11 - In Rust 1.36 or later, use newly stable MaybeUninit. This extends the diff -Nru rust-arrayvec-0.4.11/src/array.rs rust-arrayvec-0.5.1/src/array.rs --- rust-arrayvec-0.4.11/src/array.rs 2019-07-10 14:39:09.000000000 +0000 +++ rust-arrayvec-0.5.1/src/array.rs 2019-10-09 14:32:55.000000000 +0000 @@ -12,37 +12,45 @@ /// (a few in this range are included by default). /// - `array-sizes-129-255`: All sizes 129 to 255 are implemented /// (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]; } pub trait Index : PartialEq + Copy { fn to_usize(self) -> usize; - fn from(usize) -> Self; + fn from(_: usize) -> Self; } -use std::slice::{from_raw_parts}; - -pub trait ArrayExt : Array { +impl Index for () { #[inline(always)] - fn as_slice(&self) -> &[Self::Item] { - unsafe { - from_raw_parts(self.as_ptr(), Self::capacity()) - } - } + fn to_usize(self) -> usize { 0 } + #[inline(always)] + fn from(_ix: usize) -> Self { () } } -impl ArrayExt for A where A: Array { } +impl Index for bool { + #[inline(always)] + fn to_usize(self) -> usize { self as usize } + #[inline(always)] + fn from(ix: usize) -> Self { ix != 0 } +} impl Index for u8 { #[inline(always)] @@ -77,15 +85,11 @@ unsafe impl Array for [T; $len] { type Item = T; type Index = $index_type; + const CAPACITY: usize = $len; #[doc(hidden)] - #[inline(always)] - fn as_ptr(&self) -> *const T { self as *const _ as *const _ } - #[doc(hidden)] - #[inline(always)] - fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _} + fn as_slice(&self) -> &[Self::Item] { self } #[doc(hidden)] - #[inline(always)] - fn capacity() -> usize { $len } + fn as_mut_slice(&mut self) -> &mut [Self::Item] { self } } ) } @@ -97,7 +101,10 @@ ); } -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, 28, 29, 30, 31, ); diff -Nru rust-arrayvec-0.4.11/src/array_string.rs rust-arrayvec-0.5.1/src/array_string.rs --- rust-arrayvec-0.4.11/src/array_string.rs 2019-07-10 14:39:09.000000000 +0000 +++ rust-arrayvec-0.5.1/src/array_string.rs 2019-10-09 14:32:55.000000000 +0000 @@ -2,21 +2,23 @@ use std::cmp; use std::fmt; 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. /// /// The `ArrayString` is a string backed by a fixed size array. It keeps track @@ -25,20 +27,25 @@ /// The string is a contiguous value that you can store directly on the stack /// if needed. #[derive(Copy)] -pub struct ArrayString> { - // FIXME: Use Copyable union for xs when we can - xs: A, +pub struct ArrayString + where A: Array + Copy +{ + xs: MaybeUninitCopy, len: A::Index, } -impl> Default for ArrayString { +impl Default for ArrayString + where A: Array + Copy +{ /// Return an empty `ArrayString` fn default() -> ArrayString { ArrayString::new() } } -impl> ArrayString { +impl ArrayString + where A: Array + Copy +{ /// Create a new empty `ArrayString`. /// /// Capacity is inferred from the type parameter. @@ -54,13 +61,16 @@ pub fn new() -> ArrayString { unsafe { ArrayString { - // FIXME: Use Copyable union for xs when we can - xs: mem::zeroed(), + xs: MaybeUninitCopy::uninitialized(), len: Index::from(0), } } } + /// Return the length of the string. + #[inline] + pub fn len(&self) -> usize { self.len.to_usize() } + /// Create a new `ArrayString` from a `str`. /// /// Capacity is inferred from the type parameter. @@ -91,11 +101,12 @@ /// let string = ArrayString::from_byte_string(b"hello world").unwrap(); /// ``` pub fn from_byte_string(b: &A) -> Result { - 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), + }) } /// Return the capacity of the `ArrayString`. @@ -106,8 +117,8 @@ /// let string = ArrayString::<[_; 3]>::new(); /// assert_eq!(string.capacity(), 3); /// ``` - #[inline] - pub fn capacity(&self) -> usize { A::capacity() } + #[inline(always)] + pub fn capacity(&self) -> usize { A::CAPACITY } /// Return if the `ArrayString` is completely filled. /// @@ -160,7 +171,9 @@ pub fn try_push(&mut self, c: char) -> Result<(), CapacityError> { let len = self.len(); unsafe { - match encode_utf8(c, &mut self.raw_mut_bytes()[len..]) { + let ptr = self.xs.ptr_mut().add(len); + let remaining_cap = self.capacity() - len; + match encode_utf8(c, ptr, remaining_cap) { Ok(n) => { self.set_len(len + n); Ok(()) @@ -213,7 +226,7 @@ return Err(CapacityError::new(s)); } 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(); ptr::copy_nonoverlapping(src, dst, s.len()); let newl = self.len() + s.len(); @@ -237,7 +250,6 @@ /// /// assert_eq!(s.pop(), None); /// ``` - #[inline] pub fn pop(&mut self) -> Option { let ch = match self.chars().rev().next() { Some(ch) => ch, @@ -266,7 +278,6 @@ /// string.truncate(4); /// assert_eq!(&string[..], "foo"); /// ``` - #[inline] pub fn truncate(&mut self, new_len: usize) { if new_len <= self.len() { assert!(self.is_char_boundary(new_len)); @@ -297,7 +308,6 @@ /// assert_eq!(s.remove(1), 'o'); /// assert_eq!(s.remove(0), 'o'); /// ``` - #[inline] pub fn remove(&mut self, idx: usize) -> char { let ch = match self[idx..].chars().next() { Some(ch) => ch, @@ -307,8 +317,8 @@ let next = idx + ch.len_utf8(); let len = self.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); self.set_len(len - (next - idx)); } @@ -329,7 +339,6 @@ /// /// This method uses *debug assertions* to check the validity of `length` /// and may use other debug assertions. - #[inline] pub unsafe fn set_len(&mut self, length: usize) { debug_assert!(length <= self.capacity()); self.len = Index::from(length); @@ -339,79 +348,97 @@ pub fn as_str(&self) -> &str { self } - - /// Return a mutable slice of the whole string’s buffer - unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] { - slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity()) - } } -impl> Deref for ArrayString { +impl Deref for ArrayString + where A: Array + Copy +{ type Target = str; #[inline] fn deref(&self) -> &str { 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) } } } -impl> DerefMut for ArrayString { +impl DerefMut for ArrayString + where A: Array + 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) } } } -impl> PartialEq for ArrayString { +impl PartialEq for ArrayString + where A: Array + Copy +{ fn eq(&self, rhs: &Self) -> bool { **self == **rhs } } -impl> PartialEq for ArrayString { +impl PartialEq for ArrayString + where A: Array + Copy +{ fn eq(&self, rhs: &str) -> bool { &**self == rhs } } -impl> PartialEq> for str { +impl PartialEq> for str + where A: Array + Copy +{ fn eq(&self, rhs: &ArrayString) -> bool { self == &**rhs } } -impl> Eq for ArrayString { } - -impl> Hash for ArrayString { +impl Eq for ArrayString + where A: Array + Copy +{ } + +impl Hash for ArrayString + where A: Array + Copy +{ fn hash(&self, h: &mut H) { (**self).hash(h) } } -impl> Borrow for ArrayString { +impl Borrow for ArrayString + where A: Array + Copy +{ fn borrow(&self) -> &str { self } } -impl> AsRef for ArrayString { +impl AsRef for ArrayString + where A: Array + Copy +{ fn as_ref(&self) -> &str { self } } -impl> fmt::Debug for ArrayString { +impl fmt::Debug for ArrayString + where A: Array + Copy +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } } -impl> fmt::Display for ArrayString { +impl fmt::Display for ArrayString + where A: Array + Copy +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } } /// `Write` appends written data to the end of the string. -impl> fmt::Write for ArrayString { +impl fmt::Write for ArrayString + where A: Array + Copy +{ fn write_char(&mut self, c: char) -> fmt::Result { self.try_push(c).map_err(|_| fmt::Error) } @@ -421,7 +448,9 @@ } } -impl + Copy> Clone for ArrayString { +impl Clone for ArrayString + where A: Array + Copy +{ fn clone(&self) -> ArrayString { *self } @@ -432,7 +461,9 @@ } } -impl> PartialOrd for ArrayString { +impl PartialOrd for ArrayString + where A: Array + Copy +{ fn partial_cmp(&self, rhs: &Self) -> Option { (**self).partial_cmp(&**rhs) } @@ -442,7 +473,9 @@ fn ge(&self, rhs: &Self) -> bool { **self >= **rhs } } -impl> PartialOrd for ArrayString { +impl PartialOrd for ArrayString + where A: Array + Copy +{ fn partial_cmp(&self, rhs: &str) -> Option { (**self).partial_cmp(rhs) } @@ -452,7 +485,9 @@ fn ge(&self, rhs: &str) -> bool { &**self >= rhs } } -impl> PartialOrd> for str { +impl PartialOrd> for str + where A: Array + Copy +{ fn partial_cmp(&self, rhs: &ArrayString) -> Option { self.partial_cmp(&**rhs) } @@ -462,15 +497,29 @@ fn ge(&self, rhs: &ArrayString) -> bool { self >= &**rhs } } -impl> Ord for ArrayString { +impl Ord for ArrayString + where A: Array + Copy +{ fn cmp(&self, rhs: &Self) -> cmp::Ordering { (**self).cmp(&**rhs) } } -#[cfg(feature="serde-1")] -/// Requires crate feature `"serde-1"` -impl> Serialize for ArrayString { +impl FromStr for ArrayString + where A: Array + Copy +{ + type Err = CapacityError; + + fn from_str(s: &str) -> Result { + Self::from(s).map_err(CapacityError::simplify) + } +} + +#[cfg(feature="serde")] +/// Requires crate feature `"serde"` +impl Serialize for ArrayString + where A: Array + Copy +{ fn serialize(&self, serializer: S) -> Result where S: Serializer { @@ -478,9 +527,11 @@ } } -#[cfg(feature="serde-1")] -/// Requires crate feature `"serde-1"` -impl<'de, A: Array> Deserialize<'de> for ArrayString { +#[cfg(feature="serde")] +/// Requires crate feature `"serde"` +impl<'de, A> Deserialize<'de> for ArrayString + where A: Array + Copy +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { @@ -489,11 +540,11 @@ struct ArrayStringVisitor>(PhantomData); - impl<'de, A: Array> Visitor<'de> for ArrayStringVisitor { + impl<'de, A: Copy + Array> Visitor<'de> for ArrayStringVisitor { type Value = ArrayString; 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) } fn visit_str(self, v: &str) -> Result @@ -505,7 +556,7 @@ fn visit_bytes(self, v: &[u8]) -> Result where E: de::Error, { - 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))?; ArrayString::from(s).map_err(|_| E::invalid_length(s.len(), &self)) } diff -Nru rust-arrayvec-0.4.11/src/char.rs rust-arrayvec-0.5.1/src/char.rs --- rust-arrayvec-0.4.11/src/char.rs 2018-11-28 14:58:48.000000000 +0000 +++ rust-arrayvec-0.5.1/src/char.rs 2019-10-09 14:32:55.000000000 +0000 @@ -10,6 +10,8 @@ // // Original authors: alexchrichton, bluss +use std::ptr; + // UTF-8 ranges and tags for encoding characters const TAG_CONT: u8 = 0b1000_0000; const TAG_TWO_B: u8 = 0b1100_0000; @@ -22,33 +24,75 @@ /// Placeholder pub struct EncodeUtf8Error; +#[inline] +unsafe fn write(ptr: *mut u8, index: usize, byte: u8) { + ptr::write(ptr.add(index), byte) +} + /// Encode a char into buf using UTF-8. /// /// On success, return the byte length of the encoding (1, 2, 3 or 4).
/// On error, return `EncodeUtf8Error` if the buffer was too short for the char. +/// +/// Safety: `ptr` must be writable for `len` bytes. #[inline] -pub fn encode_utf8(ch: char, buf: &mut [u8]) -> Result +pub unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result { let code = ch as u32; - if code < MAX_ONE_B && buf.len() >= 1 { - buf[0] = code as u8; + if code < MAX_ONE_B && len >= 1 { + write(ptr, 0, code as u8); return Ok(1); - } else if code < MAX_TWO_B && buf.len() >= 2 { - buf[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - buf[1] = (code & 0x3F) as u8 | TAG_CONT; + } else if code < MAX_TWO_B && len >= 2 { + write(ptr, 0, (code >> 6 & 0x1F) as u8 | TAG_TWO_B); + write(ptr, 1, (code & 0x3F) as u8 | TAG_CONT); return Ok(2); - } else if code < MAX_THREE_B && buf.len() >= 3 { - buf[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - buf[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[2] = (code & 0x3F) as u8 | TAG_CONT; + } else if code < MAX_THREE_B && len >= 3 { + write(ptr, 0, (code >> 12 & 0x0F) as u8 | TAG_THREE_B); + write(ptr, 1, (code >> 6 & 0x3F) as u8 | TAG_CONT); + write(ptr, 2, (code & 0x3F) as u8 | TAG_CONT); return Ok(3); - } else if buf.len() >= 4 { - buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; - buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; + } else if len >= 4 { + write(ptr, 0, (code >> 18 & 0x07) as u8 | TAG_FOUR_B); + write(ptr, 1, (code >> 12 & 0x3F) as u8 | TAG_CONT); + write(ptr, 2, (code >> 6 & 0x3F) as u8 | TAG_CONT); + write(ptr, 3, (code & 0x3F) as u8 | TAG_CONT); return Ok(4); }; Err(EncodeUtf8Error) } + +#[test] +fn test_encode_utf8() { + // Test that all codepoints are encoded correctly + let mut data = [0u8; 16]; + for codepoint in 0..=(std::char::MAX as u32) { + if let Some(ch) = std::char::from_u32(codepoint) { + for elt in &mut data { *elt = 0; } + let ptr = data.as_mut_ptr(); + let len = data.len(); + unsafe { + let res = encode_utf8(ch, ptr, len).ok().unwrap(); + assert_eq!(res, ch.len_utf8()); + } + let string = std::str::from_utf8(&data).unwrap(); + assert_eq!(string.chars().next(), Some(ch)); + } + } +} + +#[test] +fn test_encode_utf8_oob() { + // test that we report oob if the buffer is too short + let mut data = [0u8; 16]; + let chars = ['a', 'α', '�', '𐍈']; + for (len, &ch) in (1..=4).zip(&chars) { + assert_eq!(len, ch.len_utf8(), "Len of ch={}", ch); + let ptr = data.as_mut_ptr(); + unsafe { + assert!(matches::matches!(encode_utf8(ch, ptr, len - 1), Err(_))); + assert!(matches::matches!(encode_utf8(ch, ptr, len), Ok(_))); + } + } +} + diff -Nru rust-arrayvec-0.4.11/src/lib.rs rust-arrayvec-0.5.1/src/lib.rs --- rust-arrayvec-0.4.11/src/lib.rs 2019-07-10 15:23:29.000000000 +0000 +++ rust-arrayvec-0.5.1/src/lib.rs 2019-10-09 14:38:50.000000000 +0000 @@ -7,38 +7,31 @@ //! - Optional, enabled by default //! - Use libstd; disable to use `no_std` instead. //! -//! - `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` //! - Optional //! - Enable more array sizes (see [Array] for more information) //! //! ## Rust Version //! -//! 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; #[cfg(not(feature="std"))] extern crate core as std; -#[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; // extra traits @@ -50,31 +43,21 @@ use std::io; -#[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}; mod array; mod array_string; 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; /// A vector with a fixed capacity. @@ -151,8 +134,8 @@ /// let array = ArrayVec::from([1, 2, 3]); /// assert_eq!(array.capacity(), 3); /// ``` - #[inline] - pub fn capacity(&self) -> usize { A::capacity() } + #[inline(always)] + pub fn capacity(&self) -> usize { A::CAPACITY } /// Return if the `ArrayVec` is completely filled. /// @@ -166,6 +149,19 @@ /// ``` pub fn is_full(&self) -> bool { self.len() == self.capacity() } + /// 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. /// /// ***Panics*** if the vector is already full. @@ -207,7 +203,7 @@ /// assert!(overflow.is_err()); /// ``` pub fn try_push(&mut self, element: A::Item) -> Result<(), CapacityError> { - if self.len() < A::capacity() { + if self.len() < A::CAPACITY { unsafe { self.push_unchecked(element); } @@ -239,14 +235,18 @@ /// /// assert_eq!(&array[..], &[1, 2]); /// ``` - #[inline] pub unsafe fn push_unchecked(&mut self, element: A::Item) { let len = self.len(); - debug_assert!(len < A::capacity()); - ptr::write(self.get_unchecked_mut(len), element); + debug_assert!(len < A::CAPACITY); + ptr::write(self.get_unchecked_ptr(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().add(index) + } + /// Insert `element` at position `index`. /// /// Shift up all elements after `index`. @@ -304,7 +304,7 @@ unsafe { // infallible // The spot to put the new value { - let p: *mut _ = self.get_unchecked_mut(index); + let p: *mut _ = self.get_unchecked_ptr(index); // Shift everything over to make space. (Duplicating the // `index`th element into two consecutive places.) ptr::copy(p, p.offset(1), len - index); @@ -333,12 +333,12 @@ /// ``` pub fn pop(&mut self) -> Option { if self.len() == 0 { - return None + return None; } unsafe { let new_len = self.len() - 1; self.set_len(new_len); - Some(ptr::read(self.get_unchecked_mut(new_len))) + Some(ptr::read(self.get_unchecked_ptr(new_len))) } } @@ -455,13 +455,19 @@ /// array.truncate(4); /// assert_eq!(&array[..], &[1, 2, 3]); /// ``` - 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); + } + } } /// Remove all elements in the vector. pub fn clear(&mut self) { - while let Some(_) = self.pop() { } + self.truncate(0) } /// Retains only the elements specified by the predicate. @@ -503,14 +509,49 @@ /// This method is `unsafe` because it changes the notion of the /// number of “valid” elements in the vector. Use with care. /// - /// 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. - #[inline] pub unsafe fn set_len(&mut self, length: usize) { debug_assert!(length <= self.capacity()); self.len = Index::from(length); } + /// 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 /// and yields the removed items from start to end. The element range is /// removed even if the iterator is not consumed until the end. @@ -529,11 +570,13 @@ /// assert_eq!(&v[..], &[3]); /// assert_eq!(&u[..], &[1, 2]); /// ``` - pub fn drain(&mut self, range: R) -> Drain
{ + pub fn drain(&mut self, range: R) -> Drain + where R: RangeBounds + { // 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. // // Drain will ptr::read out the values to remove. @@ -541,8 +584,22 @@ // the hole, and the vector length is restored to the new length. // 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 + { + let len = self.len(); // bounds check happens here let range_slice: *const _ = &self[start..end]; @@ -562,9 +619,6 @@ /// /// Return an `Ok` value with the array if length equals capacity, /// 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 { if self.len() < self.capacity() { Err(self) @@ -577,7 +631,8 @@ } } - /// Dispose of `self` without the overwriting that is needed in Drop. + /// Dispose of `self` (same as drop) + #[deprecated="Use std::mem::drop instead, if at all needed."] pub fn dispose(mut self) { self.clear(); mem::forget(self); @@ -592,6 +647,16 @@ pub fn as_mut_slice(&mut self) -> &mut [A::Item] { self } + + /// Return a raw pointer to the vector's buffer. + pub fn as_ptr(&self) -> *const A::Item { + self.xs.ptr() + } + + /// Return a raw mutable pointer to the vector's buffer. + pub fn as_mut_ptr(&mut self) -> *mut A::Item { + self.xs.ptr_mut() + } } impl Deref for ArrayVec { @@ -625,7 +690,7 @@ /// ``` impl From for ArrayVec { 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) } } } @@ -693,7 +758,6 @@ impl Iterator for IntoIter { type Item = A::Item; - #[inline] fn next(&mut self) -> Option { if self.index == self.v.len { None @@ -701,7 +765,7 @@ unsafe { let index = self.index.to_usize(); self.index = Index::from(index + 1); - Some(ptr::read(self.v.get_unchecked_mut(index))) + Some(ptr::read(self.v.get_unchecked_ptr(index))) } } } @@ -713,7 +777,6 @@ } impl DoubleEndedIterator for IntoIter { - #[inline] fn next_back(&mut self) -> Option { if self.index == self.v.len { None @@ -721,7 +784,7 @@ unsafe { let new_len = self.v.len() - 1; self.v.set_len(new_len); - Some(ptr::read(self.v.get_unchecked_mut(new_len))) + Some(ptr::read(self.v.get_unchecked_ptr(new_len))) } } } @@ -737,7 +800,7 @@ unsafe { self.v.set_len(0); let elements = slice::from_raw_parts_mut( - self.v.get_unchecked_mut(index), + self.v.get_unchecked_ptr(index), len - index); ptr::drop_in_place(elements); } @@ -790,7 +853,6 @@ { type Item = A::Item; - #[inline] fn next(&mut self) -> Option { self.iter.next().map(|elt| unsafe { @@ -799,7 +861,6 @@ ) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } @@ -808,7 +869,6 @@ impl<'a, A: Array> DoubleEndedIterator for Drain<'a, A> where A::Item: 'a, { - #[inline] fn next_back(&mut self) -> Option { self.iter.next_back().map(|elt| unsafe { @@ -871,27 +931,52 @@ let take = self.capacity() - self.len(); unsafe { 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 // exit. To help the compiler with alias analysis and stuff. // We update the length to handle panic in the iteration of the // user's iterator, without dropping any elements on the floor. 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; + } } } } } +/// Rawptr add but uses arithmetic distance for ZST +unsafe fn raw_ptr_add(ptr: *mut T, offset: usize) -> *mut T { + if mem::size_of::() == 0 { + // Special case for ZST + (ptr as usize).wrapping_add(offset) as _ + } else { + ptr.offset(offset as isize) + } +} + +unsafe fn raw_ptr_write(ptr: *mut T, value: T) { + if mem::size_of::() == 0 { + /* nothing */ + } else { + ptr::write(ptr, value) + } +} + /// Create an `ArrayVec` from an iterator. /// /// Does not extract more items than there is space for. No error @@ -982,27 +1067,22 @@ } impl PartialOrd for ArrayVec where A::Item: PartialOrd { - #[inline] fn partial_cmp(&self, other: &ArrayVec) -> Option { (**self).partial_cmp(other) } - #[inline] fn lt(&self, other: &Self) -> bool { (**self).lt(other) } - #[inline] fn le(&self, other: &Self) -> bool { (**self).le(other) } - #[inline] fn ge(&self, other: &Self) -> bool { (**self).ge(other) } - #[inline] fn gt(&self, other: &Self) -> bool { (**self).gt(other) } @@ -1020,22 +1100,16 @@ /// Requires `features="std"`. impl> io::Write for ArrayVec { fn write(&mut self, data: &[u8]) -> io::Result { - unsafe { - let len = self.len(); - let mut tail = slice::from_raw_parts_mut(self.get_unchecked_mut(len), - A::capacity() - len); - let result = tail.write(data); - if let Ok(written) = result { - self.set_len(len + written); - } - result - } + 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) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[cfg(feature="serde-1")] -/// Requires crate feature `"serde-1"` +#[cfg(feature="serde")] +/// Requires crate feature `"serde"` impl> Serialize for ArrayVec { fn serialize(&self, serializer: S) -> Result where S: Serializer @@ -1044,8 +1118,8 @@ } } -#[cfg(feature="serde-1")] -/// Requires crate feature `"serde-1"` +#[cfg(feature="serde")] +/// Requires crate feature `"serde"` impl<'de, T: Deserialize<'de>, A: Array> Deserialize<'de> for ArrayVec { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> @@ -1059,7 +1133,7 @@ type Value = ArrayVec; 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) } fn visit_seq(self, mut seq: SA) -> Result @@ -1067,9 +1141,9 @@ { let mut values = ArrayVec::::new(); - 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)); } } diff -Nru rust-arrayvec-0.4.11/src/maybe_uninit_nodrop.rs rust-arrayvec-0.5.1/src/maybe_uninit_nodrop.rs --- rust-arrayvec-0.4.11/src/maybe_uninit_nodrop.rs 2018-12-22 13:19:42.000000000 +0000 +++ rust-arrayvec-0.5.1/src/maybe_uninit_nodrop.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ - -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(NoDrop); -// why don't we use ManuallyDrop here: It doesn't inhibit -// enum layout optimizations that depend on T, and we support older Rust. - -impl MaybeUninit { - /// 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 _ - } -} - diff -Nru rust-arrayvec-0.4.11/src/maybe_uninit.rs rust-arrayvec-0.5.1/src/maybe_uninit.rs --- rust-arrayvec-0.4.11/src/maybe_uninit.rs 2019-07-10 14:31:06.000000000 +0000 +++ rust-arrayvec-0.5.1/src/maybe_uninit.rs 2019-10-09 14:32:55.000000000 +0000 @@ -1,27 +1,28 @@ -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 { - empty: (), - value: ManuallyDrop, +#[derive(Copy)] +pub struct MaybeUninit { + inner: StdMaybeUninit, +} + +impl Clone for MaybeUninit + where T: Copy +{ + fn clone(&self) -> Self { *self } } -// Why we don't use std's MaybeUninit on nightly? See the ptr method impl MaybeUninit { /// Create a new MaybeUninit with uninitialized interior pub unsafe fn uninitialized() -> Self { - MaybeUninit { empty: () } + MaybeUninit { inner: StdMaybeUninit::uninit() } } /// Create a new MaybeUninit from the value `v`. pub fn from(v: T) -> Self { - MaybeUninit { value: ManuallyDrop::new(v) } + MaybeUninit { inner: StdMaybeUninit::new(v) } } // Raw pointer casts written so that we don't reference or access the @@ -31,16 +32,13 @@ 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 as *const _ as *const T::Item + 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 as *mut _ as *mut T::Item + self.inner.as_mut_ptr() as *mut T::Item } } diff -Nru rust-arrayvec-0.4.11/src/maybe_uninit_stable.rs rust-arrayvec-0.5.1/src/maybe_uninit_stable.rs --- rust-arrayvec-0.4.11/src/maybe_uninit_stable.rs 2019-07-10 15:23:29.000000000 +0000 +++ rust-arrayvec-0.5.1/src/maybe_uninit_stable.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ - - -use array::Array; -use std::mem::MaybeUninit as StdMaybeUninit; - -pub struct MaybeUninit { - inner: StdMaybeUninit, -} - -impl MaybeUninit { - /// 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 - } -} diff -Nru rust-arrayvec-0.4.11/src/range.rs rust-arrayvec-0.5.1/src/range.rs --- rust-arrayvec-0.4.11/src/range.rs 2018-11-28 14:58:48.000000000 +0000 +++ rust-arrayvec-0.5.1/src/range.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ - -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 { None } - #[inline] - /// End index (exclusive) - fn end(&self) -> Option { None } -} - - -impl RangeArgument for RangeFull {} - -impl RangeArgument for RangeFrom { - #[inline] - fn start(&self) -> Option { Some(self.start) } -} - -impl RangeArgument for RangeTo { - #[inline] - fn end(&self) -> Option { Some(self.end) } -} - -impl RangeArgument for Range { - #[inline] - fn start(&self) -> Option { Some(self.start) } - #[inline] - fn end(&self) -> Option { Some(self.end) } -} - diff -Nru rust-arrayvec-0.4.11/tests/serde.rs rust-arrayvec-0.5.1/tests/serde.rs --- rust-arrayvec-0.4.11/tests/serde.rs 2018-11-28 14:58:48.000000000 +0000 +++ rust-arrayvec-0.5.1/tests/serde.rs 2019-10-09 14:32:55.000000000 +0000 @@ -1,4 +1,4 @@ -#![cfg(feature = "serde-1")] +#![cfg(feature = "serde")] extern crate arrayvec; extern crate serde_test; diff -Nru rust-arrayvec-0.4.11/tests/tests.rs rust-arrayvec-0.5.1/tests/tests.rs --- rust-arrayvec-0.4.11/tests/tests.rs 2019-07-10 15:23:29.000000000 +0000 +++ rust-arrayvec-0.5.1/tests/tests.rs 2019-10-09 14:32:55.000000000 +0000 @@ -28,6 +28,44 @@ } #[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() { const N: usize = 4096; let mut vec: ArrayVec<[_; N]> = ArrayVec::new(); @@ -127,6 +165,80 @@ } #[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); + + // 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() { let mut range = 0..10; @@ -146,8 +258,8 @@ #[test] fn test_is_send_sync() { let data = ArrayVec::<[Vec; 5]>::new(); - &data as &Send; - &data as &Sync; + &data as &dyn Send; + &data as &dyn Sync; } #[test] @@ -158,6 +270,11 @@ println!("{}", mem::size_of::()); assert!(mem::size_of::() <= 8); + // 1 enum tag + 1 drop flag + type EmptyArray = ArrayVec<[u8; 0]>; + println!("{}", mem::size_of::()); + assert!(mem::size_of::() <= 2); + // 12 element size + 1 enum tag + 3 padding + 1 len + 1 drop flag + 2 padding type QuadArray = ArrayVec<[u32; 3]>; println!("{}", mem::size_of::()); @@ -190,6 +307,29 @@ } #[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() { let mut v = ArrayVec::from([0; 8]); for (i, elt) in v.iter_mut().enumerate() { @@ -294,6 +434,7 @@ assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]); } +#[cfg(feature="std")] #[test] fn test_write() { use std::io::Write; @@ -328,6 +469,7 @@ assert_eq!(&t, &reference[..]); } +#[cfg(feature="std")] #[test] fn test_string() { use std::error::Error; @@ -353,9 +495,9 @@ assert_eq!(tmut, "ab"); // Test Error trait / try - let t = || -> Result<(), Box> { + let t = || -> Result<(), Box> { let mut t = ArrayString::<[_; 2]>::new(); - try!(t.try_push_str(text)); + t.try_push_str(text)?; Ok(()) }(); assert!(t.is_err()); @@ -371,6 +513,14 @@ } #[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() { let text = "hello world"; let u = ArrayString::from_byte_string(b"hello world").unwrap(); @@ -508,10 +658,22 @@ ArrayVec::from([0u8; 255]); } - #[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)); - } +fn test_extend_zst() { + let mut range = 0..10; + #[derive(Copy, Clone, PartialEq, Debug)] + struct Z; // Zero sized type + + 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); } diff -Nru rust-arrayvec-0.4.11/.travis.yml rust-arrayvec-0.5.1/.travis.yml --- rust-arrayvec-0.4.11/.travis.yml 2019-07-10 15:23:29.000000000 +0000 +++ rust-arrayvec-0.5.1/.travis.yml 2019-10-09 14:32:55.000000000 +0000 @@ -1,47 +1,38 @@ language: rust sudo: false env: - - FEATURES='serde-1' + - FEATURES='serde' matrix: include: - - rust: 1.13.0 - - rust: stable - env: - - NODEFAULT=1 - - NODROP_FEATURES='use_needs_drop' - - rust: 1.22.1 + - rust: 1.36.0 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: only: - master - 0.4 script: - | - ([ ! -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