1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#![cfg_attr(missing_sync_backend, allow(unused))]
#[cfg(not(has_maybe_uninit))]
pub use self::fallback_untagged_option::UntaggedOptionCell;
#[cfg(has_maybe_uninit)]
pub use self::modern_untagged_option::UntaggedOptionCell;
#[cfg(has_maybe_uninit)]
#[cfg_attr(has_maybe_uninit, clippy::msrv = "1.36")]
mod modern_untagged_option {
use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
/// An [`UnsafeCell<Option<T>>`] where the tag is not actually stored.
///
/// On versions where [`MaybeUninit`] is supported,
/// this is equivalent to a `Cell<MaybeUninit<T>>`.
/// Using uninitialized memory directly, without a `MaybeUninit`,
/// has massive potential to cause undefined behavior.
/// For this reason, on versions where [`MaybeUninit`] is unsupported,
/// this emulates [`MaybeUninit`] behavior using an `Option`.
///
/// This is not guaranteed to be `#[repr(transparent)`] due to emulation on old versions.
///
/// Cannot directly emulate [`MaybeUninit`],
/// because [`Self::assume_present`] is immediately undefined behavior when uninitialized,
/// where [`MaybeUninit::as_ptr`] is only UB if the pointer is actually dereferenced.
pub struct UntaggedOptionCell<T>(UnsafeCell<MaybeUninit<T>>);
impl<T> UntaggedOptionCell<T> {
#[inline]
pub const fn uninit() -> Self {
UntaggedOptionCell(UnsafeCell::new(MaybeUninit::uninit()))
}
/// Initialize the value to the specified value,
/// discarding any previous value.
///
/// # Safety
/// Undefined behavior if a data race occurs.
#[inline]
pub unsafe fn write(&self, value: T) {
// SAFETY: Caller guarantees mutation is valid
unsafe { self.0.get().write(MaybeUninit::new(value)) }
}
/// Assume the value is present, and get a pointer to it.
///
/// # Safety
/// Immediate undefined behavior if the option is not
#[inline]
pub const fn get_ptr_unchecked(&self) -> *mut T {
self.0.get() as *mut T
}
}
}
#[allow(clippy::missing_safety_doc)] // same behavior as 'modern' type
#[cfg(not(has_maybe_uninit))]
mod fallback_untagged_option {
use core::cell::UnsafeCell;
use core::mem::ManuallyDrop;
use crate::polyfill::UncheckedUnwrap;
// NOTE: Need ManuallyDrop for consistency with MaybeUninit
pub struct UntaggedOptionCell<T>(UnsafeCell<ManuallyDrop<Option<T>>>);
impl<T> UntaggedOptionCell<T> {
#[inline]
#[rustversion::attr(since(1.32), const)] // UnsafeCell::new, ManuallyDrop::new
pub fn uninit() -> Self {
UntaggedOptionCell(UnsafeCell::new(ManuallyDrop::new(None)))
}
#[inline]
pub unsafe fn write(&self, value: T) {
// SAFETY: Caller guarantees mutation is valid
unsafe { core::ptr::write(self.0.get(), ManuallyDrop::new(Some(value))) }
}
#[inline]
pub unsafe fn get_ptr_unchecked(&self) -> *mut T {
// SAFETY: Caller guarantees not being concurrently mutated
let opt: &Option<T> = unsafe { &*self.0.get() };
// SAFETY: Caller guarantees data is initialized
unsafe { opt.as_ref().polyfill_unwrap_unchecked() as *const T as *mut T }
}
}
}
pub trait UncheckedUnwrap<T> {
/// Assume that the specified value is `Some`,
/// triggering undefined behavior if not.
///
/// # Safety
/// Undefined behavior if `None`.
unsafe fn polyfill_unwrap_unchecked(self) -> T;
}
impl<T> UncheckedUnwrap<T> for Option<T> {
//noinspection RsReplaceMatchExpr
#[inline]
unsafe fn polyfill_unwrap_unchecked(self) -> T {
#[cfg(debug_assertions)]
assert!(self.is_some());
match self {
Some(x) => x,
None => {
// SAFETY: Responsibility of caller
unsafe { core::hint::unreachable_unchecked() }
}
}
}
}
pub trait FinishNonExhaustive {
fn polyfill_finish_non_exhaustive(&mut self) -> core::fmt::Result;
}
macro_rules! do_impl_non_exhaustive {
($($target:ident),*) => {
$(impl FinishNonExhaustive for core::fmt::$target<'_, '_> {
#[rustversion::since(1.53)]
fn polyfill_finish_non_exhaustive(&mut self) -> core::fmt::Result {
self.finish_non_exhaustive()
}
#[rustversion::before(1.53)]
fn polyfill_finish_non_exhaustive(&mut self) -> core::fmt::Result {
self.finish()
}
})*
};
}
do_impl_non_exhaustive!(DebugStruct);