From b56c3b78d067ea761d3308d8e2aa2dbba4f0426b Mon Sep 17 00:00:00 2001 From: bluss Date: Wed, 10 Jul 2019 16:40:50 +0200 Subject: [PATCH 1/2] FEAT: Use stable MaybeUninit when we can (feature detected) --- build.rs | 21 +++++++++++++++----- src/lib.rs | 7 +++++-- src/maybe_uninit_stable.rs | 40 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 src/maybe_uninit_stable.rs diff --git a/build.rs b/build.rs index 1a4ac7d3..a91c5f4d 100644 --- a/build.rs +++ b/build.rs @@ -11,17 +11,28 @@ fn main() { } 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"); - return; } +} - let has_stable_union_with_md = probe(&maybe_uninit_code(false)); - if has_stable_union_with_md { - println!("cargo:rustc-cfg=has_manually_drop_in_union"); - } +// 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 diff --git a/src/lib.rs b/src/lib.rs index cd8f0b9e..1e05e59a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,9 +50,12 @@ use std::fmt; use std::io; -#[cfg(has_manually_drop_in_union)] +#[cfg(has_stable_maybe_uninit)] +#[path="maybe_uninit_stable.rs"] mod maybe_uninit; -#[cfg(not(has_manually_drop_in_union))] +#[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; diff --git a/src/maybe_uninit_stable.rs b/src/maybe_uninit_stable.rs new file mode 100644 index 00000000..cb631a9d --- /dev/null +++ b/src/maybe_uninit_stable.rs @@ -0,0 +1,40 @@ + + +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 + } +} From 93220e55ae1a20e6d65db1575635946c816ac351 Mon Sep 17 00:00:00 2001 From: bluss Date: Wed, 10 Jul 2019 16:57:48 +0200 Subject: [PATCH 2/2] TEST: Update tests for new MaybeUninit usage (Also remove the size check since we can't rely on it, even if we want to ensure it has no overhead for the bytes case.) --- .travis.yml | 5 +++-- tests/tests.rs | 8 +++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3730670d..c02af700 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ matrix: - rust: stable env: - FEATURES='array-sizes-33-128 array-sizes-129-255' + - ARRAYVECTEST_ENSURE_MAYBEUNINIT=1 - rust: beta - rust: nightly env: @@ -23,12 +24,12 @@ matrix: - rust: nightly env: - NODROP_FEATURES='use_needs_drop' - - ARRAYVECTEST_ENSURE_UNION=1 + - ARRAYVECTEST_ENSURE_MAYBEUNINIT=1 - rust: nightly env: - FEATURES='serde use_union' - NODROP_FEATURES='use_union' - - ARRAYVECTEST_ENSURE_UNION=1 + - ARRAYVECTEST_ENSURE_MAYBEUNINIT=1 branches: only: - master diff --git a/tests/tests.rs b/tests/tests.rs index 0e694672..b8dbadb2 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -510,10 +510,8 @@ fn test_sizes_129_255() { #[test] -fn test_nightly_uses_maybe_uninit() { - if option_env!("ARRAYVECTEST_ENSURE_UNION").map(|s| !s.is_empty()).unwrap_or(false) { - assert!(cfg!(has_manually_drop_in_union)); - type ByteArray = ArrayVec<[u8; 4]>; - assert!(mem::size_of::() == 5); +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)); } }