Implement ACP 429: add Lazy{Cell,Lock}::get[_mut]
and force_mut
· qinheping/verify-rust-std@a0f4a4b (original) (raw)
1
1
`use super::UnsafeCell;
`
2
``
`-
use crate::ops::Deref;
`
``
2
`+
use crate::hint::unreachable_unchecked;
`
``
3
`+
use crate::ops::{Deref, DerefMut};
`
3
4
`use crate::{fmt, mem};
`
4
5
``
5
6
`enum State<T, F> {
`
`@@ -82,7 +83,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
`
82
83
`match this.state.into_inner() {
`
83
84
`State::Init(data) => Ok(data),
`
84
85
`State::Uninit(f) => Err(f),
`
85
``
`-
State::Poisoned => panic!("LazyCell instance has previously been poisoned"),
`
``
86
`+
State::Poisoned => panic_poisoned(),
`
86
87
`}
`
87
88
`}
`
88
89
``
`@@ -114,7 +115,75 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
`
114
115
`State::Init(data) => data,
`
115
116
`// SAFETY: The state is uninitialized.
`
116
117
`State::Uninit(_) => unsafe { LazyCell::really_init(this) },
`
117
``
`-
State::Poisoned => panic!("LazyCell has previously been poisoned"),
`
``
118
`+
State::Poisoned => panic_poisoned(),
`
``
119
`+
}
`
``
120
`+
}
`
``
121
+
``
122
`+
/// Forces the evaluation of this lazy value and returns a mutable reference to
`
``
123
`+
/// the result.
`
``
124
`+
///
`
``
125
`` +
/// This is equivalent to the DerefMut
impl, but is explicit.
``
``
126
`+
///
`
``
127
`+
/// # Examples
`
``
128
`+
///
`
``
129
/// ```
``
130
`+
/// use std::cell::LazyCell;
`
``
131
`+
///
`
``
132
`+
/// let mut lazy = LazyCell::new(|| 92);
`
``
133
`+
///
`
``
134
`+
/// let p = LazyCell::force_mut(&mut lazy);
`
``
135
`+
/// assert_eq!(*p, 92);
`
``
136
`+
/// *p = 44;
`
``
137
`+
/// assert_eq!(*lazy, 44);
`
``
138
`` +
/// *lazy = 55; // Using DerefMut
``
``
139
`+
/// assert_eq!(*lazy, 55);
`
``
140
/// ```
``
141
`+
#[inline]
`
``
142
`+
#[stable(feature = "lazy_deref_mut", since = "CURRENT_RUSTC_VERSION")]
`
``
143
`+
pub fn force_mut(this: &mut LazyCell<T, F>) -> &mut T {
`
``
144
`+
#[cold]
`
``
145
`+
/// # Safety
`
``
146
`` +
/// May only be called when the state is Uninit
.
``
``
147
`+
unsafe fn really_init<T, F: FnOnce() -> T>(state: &mut State<T, F>) -> &mut T {
`
``
148
`+
// INVARIANT: Always valid, but the value may not be dropped.
`
``
149
`+
struct PoisonOnPanic<T, F>(*mut State<T, F>);
`
``
150
`+
impl<T, F> Drop for PoisonOnPanic<T, F> {
`
``
151
`+
#[inline]
`
``
152
`+
fn drop(&mut self) {
`
``
153
`+
// SAFETY: Invariant states it is valid, and we don't drop the old value.
`
``
154
`+
unsafe {
`
``
155
`+
self.0.write(State::Poisoned);
`
``
156
`+
}
`
``
157
`+
}
`
``
158
`+
}
`
``
159
+
``
160
`+
let State::Uninit(f) = state else {
`
``
161
`` +
// unreachable!()
here won't optimize out because the function is cold.
``
``
162
`+
// SAFETY: Precondition.
`
``
163
`+
unsafe { unreachable_unchecked() };
`
``
164
`+
};
`
``
165
`` +
// SAFETY: We never drop the state after we read f
, and we write a valid value back
``
``
166
`` +
// in any case, panic or success. f
can't access the LazyCell
because it is mutably
``
``
167
`+
// borrowed.
`
``
168
`+
let f = unsafe { core::ptr::read(f) };
`
``
169
`+
// INVARIANT: Initiated from mutable reference, don't drop because we read it.
`
``
170
`+
let guard = PoisonOnPanic(state);
`
``
171
`+
let data = f();
`
``
172
`` +
// SAFETY: PoisonOnPanic
invariant, and we don't drop the old value.
``
``
173
`+
unsafe {
`
``
174
`+
core::ptr::write(guard.0, State::Init(data));
`
``
175
`+
}
`
``
176
`+
core::mem::forget(guard);
`
``
177
`+
let State::Init(data) = state else { unreachable!() };
`
``
178
`+
data
`
``
179
`+
}
`
``
180
+
``
181
`+
let state = this.state.get_mut();
`
``
182
`+
match state {
`
``
183
`+
State::Init(data) => data,
`
``
184
`` +
// SAFETY: state
is Uninit
.
``
``
185
`+
State::Uninit(_) => unsafe { really_init(state) },
`
``
186
`+
State::Poisoned => panic_poisoned(),
`
118
187
`}
`
119
188
`}
`
120
189
``
`@@ -152,13 +221,55 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
`
152
221
`}
`
153
222
``
154
223
`impl<T, F> LazyCell<T, F> {
`
``
224
`` +
/// Returns a reference to the value if initialized, or None
if not.
``
``
225
`+
///
`
``
226
`+
/// # Examples
`
``
227
`+
///
`
``
228
/// ```
``
229
`+
/// #![feature(lazy_get)]
`
``
230
`+
///
`
``
231
`+
/// use std::cell::LazyCell;
`
``
232
`+
///
`
``
233
`+
/// let mut lazy = LazyCell::new(|| 92);
`
``
234
`+
///
`
``
235
`+
/// assert_eq!(LazyCell::get_mut(&mut lazy), None);
`
``
236
`+
/// let _ = LazyCell::force(&lazy);
`
``
237
`+
/// *LazyCell::get_mut(&mut lazy).unwrap() = 44;
`
``
238
`+
/// assert_eq!(*lazy, 44);
`
``
239
/// ```
``
240
`+
#[inline]
`
``
241
`+
#[unstable(feature = "lazy_get", issue = "129333")]
`
``
242
`+
pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> {
`
``
243
`+
let state = this.state.get_mut();
`
``
244
`+
match state {
`
``
245
`+
State::Init(data) => Some(data),
`
``
246
`+
_ => None,
`
``
247
`+
}
`
``
248
`+
}
`
``
249
+
``
250
`` +
/// Returns a mutable reference to the value if initialized, or None
if not.
``
``
251
`+
///
`
``
252
`+
/// # Examples
`
``
253
`+
///
`
``
254
/// ```
``
255
`+
/// #![feature(lazy_get)]
`
``
256
`+
///
`
``
257
`+
/// use std::cell::LazyCell;
`
``
258
`+
///
`
``
259
`+
/// let lazy = LazyCell::new(|| 92);
`
``
260
`+
///
`
``
261
`+
/// assert_eq!(LazyCell::get(&lazy), None);
`
``
262
`+
/// let _ = LazyCell::force(&lazy);
`
``
263
`+
/// assert_eq!(LazyCell::get(&lazy), Some(&92));
`
``
264
/// ```
155
265
`#[inline]
`
156
``
`-
fn get(&self) -> Option<&T> {
`
``
266
`+
#[unstable(feature = "lazy_get", issue = "129333")]
`
``
267
`+
pub fn get(this: &LazyCell<T, F>) -> Option<&T> {
`
157
268
`// SAFETY:
`
158
269
`` // This is sound for the same reason as in force
: once the state is
``
159
270
`// initialized, it will not be mutably accessed again, so this reference
`
160
271
`` // will stay valid for the duration of the borrow to self
.
``
161
``
`-
let state = unsafe { &*self.state.get() };
`
``
272
`+
let state = unsafe { &*this.state.get() };
`
162
273
`match state {
`
163
274
`State::Init(data) => Some(data),
`
164
275
` _ => None,
`
`@@ -175,6 +286,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
`
175
286
`}
`
176
287
`}
`
177
288
``
``
289
`+
#[stable(feature = "lazy_deref_mut", since = "CURRENT_RUSTC_VERSION")]
`
``
290
`+
impl<T, F: FnOnce() -> T> DerefMut for LazyCell<T, F> {
`
``
291
`+
#[inline]
`
``
292
`+
fn deref_mut(&mut self) -> &mut T {
`
``
293
`+
LazyCell::force_mut(self)
`
``
294
`+
}
`
``
295
`+
}
`
``
296
+
178
297
`#[stable(feature = "lazy_cell", since = "1.80.0")]
`
179
298
`impl<T: Default> Default for LazyCell {
`
180
299
`` /// Creates a new lazy value using Default
as the initializing function.
``
`@@ -188,10 +307,16 @@ impl<T: Default> Default for LazyCell {
`
188
307
`impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> {
`
189
308
`fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
`
190
309
`let mut d = f.debug_tuple("LazyCell");
`
191
``
`-
match self.get() {
`
``
310
`+
match LazyCell::get(self) {
`
192
311
`Some(data) => d.field(data),
`
193
312
`None => d.field(&format_args!("")),
`
194
313
`};
`
195
314
` d.finish()
`
196
315
`}
`
197
316
`}
`
``
317
+
``
318
`+
#[cold]
`
``
319
`+
#[inline(never)]
`
``
320
`+
fn panic_poisoned() -> ! {
`
``
321
`+
panic!("LazyCell instance has previously been poisoned")
`
``
322
`+
}
`