diff --git a/build.rs b/build.rs index 1a4ac7d..a91c5f4 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 cd8f0b9..1e05e59 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 0000000..cb631a9 --- /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 + } +}