FEAT: Implement a "MaybeUninit" and use it conditionally
Use a build script to detect if we can use MaybeUninit or NoDrop. Enabling unstable features automatically is not ideal, but since it's a soundness issue we should do it. Use a MaybeUninit-like union on nightly when we can. We use a feature detection script in build.rs, so that we also go back to the fallback if the unstable feature changes in an unexpected way. We need to continue to use NoDrop for best working stable implementation, but we eagerly use our union solution where we can, currently only in nightlies. Rustc feature probe code written by Josh Stone (cuviper), taken from num-bigint.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
|
||||
|
||||
use array::Array;
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
/// 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.
|
||||
#[derive(Copy)]
|
||||
pub union MaybeUninit<T> {
|
||||
empty: (),
|
||||
value: ManuallyDrop<T>,
|
||||
}
|
||||
// Why we don't use std's MaybeUninit on nightly? See the ptr method
|
||||
|
||||
impl<T> Clone for MaybeUninit<T> where T: Copy
|
||||
{
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl<T> MaybeUninit<T> {
|
||||
/// Create a new MaybeUninit with uninitialized interior
|
||||
pub unsafe fn uninitialized() -> Self {
|
||||
MaybeUninit { empty: () }
|
||||
}
|
||||
|
||||
/// Create a new MaybeUninit from the value `v`.
|
||||
pub fn from(v: T) -> Self {
|
||||
MaybeUninit { value: ManuallyDrop::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 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user