From 8093e8d886509ba7a0dc3f8a9b2153a901a22036 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 1 Sep 2019 12:18:17 +0200 Subject: [PATCH] FEAT: Switch to using MaybeUninit for everything Use std::mem::MaybeUninit and stop using nodrop as a fallback. This means we require Rust 1.36 --- .travis.yml | 8 +--- Cargo.toml | 3 -- build.rs | 90 -------------------------------------- src/array_string.rs | 8 ++-- src/lib.rs | 20 ++------- src/maybe_uninit.rs | 30 ++++++------- src/maybe_uninit_copy.rs | 43 ------------------ src/maybe_uninit_nodrop.rs | 41 ----------------- src/maybe_uninit_stable.rs | 40 ----------------- tests/tests.rs | 8 ---- 10 files changed, 22 insertions(+), 269 deletions(-) delete mode 100644 build.rs delete mode 100644 src/maybe_uninit_copy.rs delete mode 100644 src/maybe_uninit_nodrop.rs delete mode 100644 src/maybe_uninit_stable.rs diff --git a/.travis.yml b/.travis.yml index 8b5b3ac..df3009b 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 bd634c8..fb8b2eb 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/build.rs b/build.rs deleted file mode 100644 index a91c5f4..0000000 --- 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_string.rs b/src/array_string.rs index 475977b..5aa8d4e 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -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. /// diff --git a/src/lib.rs b/src/lib.rs index be734c0..0742cfc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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}; @@ -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) } } } diff --git a/src/maybe_uninit.rs b/src/maybe_uninit.rs index 9ed1f6a..4903fa3 100644 --- a/src/maybe_uninit.rs +++ b/src/maybe_uninit.rs @@ -1,27 +1,28 @@ use array::Array; -use std::mem::ManuallyDrop; +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 @@ 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 1a1c9ec..0000000 --- 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 8213b97..0000000 --- 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 cb631a9..0000000 --- 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 306689c..f8bcd0f 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;