-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement MaybeUninit
#53508
Implement MaybeUninit
#53508
Changes from all commits
7bb5b3e
851acdd
96572cb
7c37c6d
ce8503d
a6d011a
af101fd
ce6e6f9
33c10ea
bc5b567
d864edc
758ce16
8fb0e80
8482c93
7fea7f4
dd9f019
41b242e
d266722
1cdbad2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ | |
// except according to those terms. | ||
|
||
use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug}; | ||
use mem; | ||
use mem::MaybeUninit; | ||
use num::flt2dec; | ||
|
||
// Don't inline this so callers don't use the stack space this function | ||
|
@@ -20,11 +20,11 @@ fn float_to_decimal_common_exact<T>(fmt: &mut Formatter, num: &T, | |
where T: flt2dec::DecodableFloat | ||
{ | ||
unsafe { | ||
let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64 | ||
let mut parts: [flt2dec::Part; 4] = mem::uninitialized(); | ||
let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64 | ||
let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized(); | ||
let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, | ||
*num, sign, precision, | ||
false, &mut buf, &mut parts); | ||
false, buf.get_mut(), parts.get_mut()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another case of using |
||
fmt.pad_formatted_parts(&formatted) | ||
} | ||
} | ||
|
@@ -38,10 +38,11 @@ fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter, num: &T, | |
{ | ||
unsafe { | ||
// enough for f32 and f64 | ||
let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized(); | ||
let mut parts: [flt2dec::Part; 4] = mem::uninitialized(); | ||
let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized(); | ||
let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized(); | ||
let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, | ||
sign, precision, false, &mut buf, &mut parts); | ||
sign, precision, false, buf.get_mut(), | ||
parts.get_mut()); | ||
fmt.pad_formatted_parts(&formatted) | ||
} | ||
} | ||
|
@@ -75,11 +76,11 @@ fn float_to_exponential_common_exact<T>(fmt: &mut Formatter, num: &T, | |
where T: flt2dec::DecodableFloat | ||
{ | ||
unsafe { | ||
let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64 | ||
let mut parts: [flt2dec::Part; 6] = mem::uninitialized(); | ||
let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64 | ||
let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized(); | ||
let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, | ||
*num, sign, precision, | ||
upper, &mut buf, &mut parts); | ||
upper, buf.get_mut(), parts.get_mut()); | ||
fmt.pad_formatted_parts(&formatted) | ||
} | ||
} | ||
|
@@ -94,11 +95,11 @@ fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter, | |
{ | ||
unsafe { | ||
// enough for f32 and f64 | ||
let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized(); | ||
let mut parts: [flt2dec::Part; 6] = mem::uninitialized(); | ||
let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized(); | ||
let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized(); | ||
let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, | ||
*num, sign, (0, 0), upper, | ||
&mut buf, &mut parts); | ||
buf.get_mut(), parts.get_mut()); | ||
fmt.pad_formatted_parts(&formatted) | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -514,6 +514,7 @@ pub fn needs_drop<T>() -> bool { | |
/// assert_eq!(0, x); | ||
/// ``` | ||
#[inline] | ||
#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::zeroed` instead")] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
pub unsafe fn zeroed<T>() -> T { | ||
intrinsics::init() | ||
|
@@ -608,6 +609,7 @@ pub unsafe fn zeroed<T>() -> T { | |
/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html | ||
/// [`Drop`]: ../ops/trait.Drop.html | ||
#[inline] | ||
#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
pub unsafe fn uninitialized<T>() -> T { | ||
intrinsics::uninit() | ||
|
@@ -1024,3 +1026,97 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> { | |
&mut self.value | ||
} | ||
} | ||
|
||
/// A newtype to construct uninitialized instances of `T` | ||
#[allow(missing_debug_implementations)] | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
// NOTE after stabilizing `MaybeUninit` proceed to deprecate `mem::{uninitialized,zeroed}` | ||
pub union MaybeUninit<T> { | ||
uninit: (), | ||
value: ManuallyDrop<T>, | ||
} | ||
|
||
impl<T> MaybeUninit<T> { | ||
/// Create a new `MaybeUninit` in an uninitialized state. | ||
/// | ||
/// Note that dropping a `MaybeUninit` will never call `T`'s drop code. | ||
/// It is your responsibility to make sure `T` gets dropped if it got initialized. | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
pub const fn uninitialized() -> MaybeUninit<T> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need a rustc_const_unstable attribute here as well? Or at least make a note to do so eventually? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not stabilize as |
||
MaybeUninit { uninit: () } | ||
} | ||
|
||
/// Create a new `MaybeUninit` in an uninitialized state, with the memory being | ||
/// filled with `0` bytes. It depends on `T` whether that already makes for | ||
/// proper initialization. For example, `MaybeUninit<usize>::zeroed()` is initialized, | ||
/// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not | ||
/// be null. | ||
/// | ||
/// Note that dropping a `MaybeUninit` will never call `T`'s drop code. | ||
/// It is your responsibility to make sure `T` gets dropped if it got initialized. | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
pub fn zeroed() -> MaybeUninit<T> { | ||
let mut u = MaybeUninit::<T>::uninitialized(); | ||
unsafe { | ||
u.as_mut_ptr().write_bytes(0u8, 1); | ||
} | ||
u | ||
} | ||
|
||
/// Set the value of the `MaybeUninit`. This overwrites any previous value without dropping it. | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
pub fn set(&mut self, val: T) { | ||
unsafe { | ||
self.value = ManuallyDrop::new(val); | ||
} | ||
} | ||
|
||
/// Extract the value from the `MaybeUninit` container. This is a great way | ||
/// to ensure that the data will get dropped, because the resulting `T` is | ||
/// subject to the usual drop handling. | ||
/// | ||
/// # Unsafety | ||
/// | ||
/// It is up to the caller to guarantee that the the `MaybeUninit` really is in an initialized | ||
/// state, otherwise this will immediately cause undefined behavior. | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
pub unsafe fn into_inner(self) -> T { | ||
ManuallyDrop::into_inner(self.value) | ||
} | ||
|
||
/// Get a reference to the contained value. | ||
/// | ||
/// # Unsafety | ||
/// | ||
/// It is up to the caller to guarantee that the the `MaybeUninit` really is in an initialized | ||
/// state, otherwise this will immediately cause undefined behavior. | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
pub unsafe fn get_ref(&self) -> &T { | ||
&*self.value | ||
} | ||
|
||
/// Get a mutable reference to the contained value. | ||
/// | ||
/// # Unsafety | ||
/// | ||
/// It is up to the caller to guarantee that the the `MaybeUninit` really is in an initialized | ||
/// state, otherwise this will immediately cause undefined behavior. | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
pub unsafe fn get_mut(&mut self) -> &mut T { | ||
&mut *self.value | ||
} | ||
|
||
/// Get a pointer to the contained value. Reading from this pointer will be undefined | ||
/// behavior unless the `MaybeUninit` is initialized. | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
pub fn as_ptr(&self) -> *const T { | ||
unsafe { &*self.value as *const T } | ||
} | ||
|
||
/// Get a mutable pointer to the contained value. Reading from this pointer will be undefined | ||
/// behavior unless the `MaybeUninit` is initialized. | ||
#[unstable(feature = "maybe_uninit", issue = "53491")] | ||
pub fn as_mut_ptr(&mut self) -> *mut T { | ||
unsafe { &mut *self.value as *mut T } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the comment above, should this instead be
[MaybeUninit<V>; CAPACITY]
?(That might be a pain, though, and this is no worse than before, so might not be this PR.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems like a pretty equivalent type to me. Which comment above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we document that you can partially-initialize
MaybeUninit
, i.e. that it "distributes over products"?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is forth saying, yes.
Unfortunately actually implementing this is not easy, same problem as for
Cell
(which also distributes over products).