diff --git a/.travis.yml b/.travis.yml index 8b5b3ac5..df3009bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ env: - FEATURES='serde-1' matrix: include: - - rust: 1.24.1 + - rust: 1.36.0 env: - FEATURES='array-sizes-33-128 array-sizes-129-255' - rust: stable @@ -14,23 +14,17 @@ matrix: - rust: stable env: - FEATURES='array-sizes-33-128 array-sizes-129-255' - - ARRAYVECTEST_ENSURE_MAYBEUNINIT=1 - rust: beta - rust: nightly - env: - - ARRAYVECTEST_ENSURE_UNION=1 - rust: nightly env: - FEATURES='serde' - - ARRAYVECTEST_ENSURE_UNION=1 - rust: nightly env: - FEATURES='serde-1' - - ARRAYVECTEST_ENSURE_UNION=1 - rust: nightly env: - FEATURES='array-sizes-33-128 array-sizes-129-255' - - ARRAYVECTEST_ENSURE_MAYBEUNINIT=1 branches: only: - master diff --git a/Cargo.toml b/Cargo.toml index bd634c89..fb8b2eb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,6 @@ categories = ["data-structures", "no-std"] [build-dependencies] -[dependencies] -nodrop = { version = "0.1.12", path = "nodrop", default-features = false } - [dependencies.serde] version = "1.0" optional = true diff --git a/README.rst b/README.rst index 6f6476fe..74985268 100644 --- a/README.rst +++ b/README.rst @@ -22,6 +22,20 @@ __ https://docs.rs/arrayvec Recent Changes (arrayvec) ------------------------- +- 0.5.0 (not released yet) + + - Add ``FromStr`` impl for ``ArrayString`` by @despawnerer + - Use a union in the implementation of ``ArrayString`` (stable Rust), + while this is only used for ``ArrayVec`` on nightly. + - 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 + @clarcharr + - Use ``drop_in_place`` for truncate and clear methods. This affects drop order + and resume from panic during drop. + - 0.4.11 - In Rust 1.36 or later, use newly stable MaybeUninit. This extends the diff --git a/build.rs b/build.rs deleted file mode 100644 index a91c5f4d..00000000 --- a/build.rs +++ /dev/null @@ -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 --git a/src/array.rs b/src/array.rs index ad18c795..ed492113 100644 --- a/src/array.rs +++ b/src/array.rs @@ -20,10 +20,8 @@ pub unsafe trait Array { type Index: Index; /// The array's element capacity const CAPACITY: usize; - #[doc(hidden)] - fn as_ptr(&self) -> *const Self::Item; - #[doc(hidden)] - fn capacity() -> usize; + fn as_slice(&self) -> &[Self::Item]; + fn as_mut_slice(&mut self) -> &mut [Self::Item]; } pub trait Index : PartialEq + Copy { @@ -31,19 +29,6 @@ pub trait Index : PartialEq + Copy { fn from(usize) -> Self; } -use std::slice::{from_raw_parts}; - -pub trait ArrayExt : Array { - #[inline(always)] - fn as_slice(&self) -> &[Self::Item] { - unsafe { - from_raw_parts(self.as_ptr(), Self::capacity()) - } - } -} - -impl ArrayExt for A where A: Array { } - impl Index for () { #[inline(always)] fn to_usize(self) -> usize { 0 } @@ -93,11 +78,11 @@ macro_rules! fix_array_impl { 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 capacity() -> usize { $len } + #[inline] + fn as_mut_slice(&mut self) -> &mut [Self::Item] { self } } ) } diff --git a/src/array_string.rs b/src/array_string.rs index d83b463f..5159dfb4 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -9,7 +9,7 @@ use std::str::FromStr; use std::str::Utf8Error; use std::slice; -use array::{Array, ArrayExt}; +use array::Array; use array::Index; use CapacityError; use char::encode_utf8; @@ -17,7 +17,7 @@ use char::encode_utf8; #[cfg(feature="serde-1")] use serde::{Serialize, Deserialize, Serializer, Deserializer}; -use super::MaybeUninitCopy; +use super::MaybeUninit as MaybeUninitCopy; /// A string with a fixed capacity. /// @@ -98,10 +98,10 @@ impl ArrayString /// ``` pub fn from_byte_string(b: &A) -> Result { let len = str::from_utf8(b.as_slice())?.len(); - debug_assert_eq!(len, A::capacity()); + debug_assert_eq!(len, A::CAPACITY); Ok(ArrayString { xs: MaybeUninitCopy::from(*b), - len: Index::from(A::capacity()), + len: Index::from(A::CAPACITY), }) } @@ -114,7 +114,7 @@ impl ArrayString /// assert_eq!(string.capacity(), 3); /// ``` #[inline] - pub fn capacity(&self) -> usize { A::capacity() } + pub fn capacity(&self) -> usize { A::CAPACITY } /// Return if the `ArrayString` is completely filled. /// @@ -547,7 +547,7 @@ impl<'de, A> Deserialize<'de> for ArrayString 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 diff --git a/src/lib.rs b/src/lib.rs index f27e3b6e..1c176fec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ //! //! ## Rust Version //! -//! This version of arrayvec requires Rust 1.24 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)] @@ -28,9 +28,6 @@ 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; @@ -50,19 +47,8 @@ use std::fmt; 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; - -mod maybe_uninit_copy; - use maybe_uninit::MaybeUninit; -use maybe_uninit_copy::MaybeUninitCopy; #[cfg(feature="serde-1")] use serde::{Serialize, Deserialize, Serializer, Deserializer}; @@ -155,7 +141,7 @@ impl ArrayVec { /// assert_eq!(array.capacity(), 3); /// ``` #[inline] - pub fn capacity(&self) -> usize { A::capacity() } + pub fn capacity(&self) -> usize { A::CAPACITY } /// Return if the `ArrayVec` is completely filled. /// @@ -223,7 +209,7 @@ impl ArrayVec { /// 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); } @@ -258,7 +244,7 @@ impl ArrayVec { #[inline] pub unsafe fn push_unchecked(&mut self, element: A::Item) { let len = self.len(); - debug_assert!(len < A::capacity()); + debug_assert!(len < A::CAPACITY); ptr::write(self.get_unchecked_mut(len), element); self.set_len(len + 1); } @@ -680,7 +666,7 @@ impl DerefMut for ArrayVec { /// ``` 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) } } } @@ -1133,7 +1119,7 @@ impl<'de, T: Deserialize<'de>, A: Array> Deserialize<'de> for 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 @@ -1143,7 +1129,7 @@ impl<'de, T: Deserialize<'de>, A: Array> Deserialize<'de> for ArrayVec { - empty: (), - value: ManuallyDrop, +use std::mem::MaybeUninit as StdMaybeUninit; + +#[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 @@ impl MaybeUninit { 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 --git a/src/maybe_uninit_copy.rs b/src/maybe_uninit_copy.rs deleted file mode 100644 index 1a1c9ec6..00000000 --- a/src/maybe_uninit_copy.rs +++ /dev/null @@ -1,43 +0,0 @@ - -use array::Array; - -#[derive(Copy, Clone)] -#[repr(C)] // for cast from self ptr to value -pub union MaybeUninitCopy - where T: Copy -{ - empty: (), - value: T, -} - -impl MaybeUninitCopy - where T: Copy -{ - /// Create a new MaybeUninit with uninitialized interior - pub unsafe fn uninitialized() -> Self { - Self { empty: () } - } - - /// Create a new MaybeUninit from the value `v`. - pub fn from(value: T) -> Self { - Self { value } - } - - // 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 - { - self as *const _ 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 - } -} - diff --git a/src/maybe_uninit_nodrop.rs b/src/maybe_uninit_nodrop.rs deleted file mode 100644 index 8213b97d..00000000 --- a/src/maybe_uninit_nodrop.rs +++ /dev/null @@ -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 --git a/src/maybe_uninit_stable.rs b/src/maybe_uninit_stable.rs deleted file mode 100644 index cb631a9d..00000000 --- a/src/maybe_uninit_stable.rs +++ /dev/null @@ -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 --git a/tests/tests.rs b/tests/tests.rs index 306689c3..f8bcd0f9 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -633,14 +633,6 @@ fn test_sizes_129_255() { 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)); - } -} - #[test] fn test_extend_zst() { let mut range = 0..10;