Rollup merge of #130476 - workingjubilee:more-lazy-methods-take-2, r=… · qinheping/verify-rust-std@f63c0c1 (original) (raw)
1
1
`use super::UnsafeCell;
`
``
2
`+
use crate::hint::unreachable_unchecked;
`
2
3
`use crate::ops::Deref;
`
3
4
`use crate::{fmt, mem};
`
4
5
``
`@@ -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,72 @@ 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
`+
/// # Examples
`
``
126
`+
///
`
``
127
/// ```
``
128
`+
/// #![feature(lazy_get)]
`
``
129
`+
/// use std::cell::LazyCell;
`
``
130
`+
///
`
``
131
`+
/// let mut lazy = LazyCell::new(|| 92);
`
``
132
`+
///
`
``
133
`+
/// let p = LazyCell::force_mut(&mut lazy);
`
``
134
`+
/// assert_eq!(*p, 92);
`
``
135
`+
/// *p = 44;
`
``
136
`+
/// assert_eq!(*lazy, 44);
`
``
137
/// ```
``
138
`+
#[inline]
`
``
139
`+
#[unstable(feature = "lazy_get", issue = "129333")]
`
``
140
`+
pub fn force_mut(this: &mut LazyCell<T, F>) -> &mut T {
`
``
141
`+
#[cold]
`
``
142
`+
/// # Safety
`
``
143
`` +
/// May only be called when the state is Uninit
.
``
``
144
`+
unsafe fn really_init_mut<T, F: FnOnce() -> T>(state: &mut State<T, F>) -> &mut T {
`
``
145
`+
// INVARIANT: Always valid, but the value may not be dropped.
`
``
146
`+
struct PoisonOnPanic<T, F>(*mut State<T, F>);
`
``
147
`+
impl<T, F> Drop for PoisonOnPanic<T, F> {
`
``
148
`+
#[inline]
`
``
149
`+
fn drop(&mut self) {
`
``
150
`+
// SAFETY: Invariant states it is valid, and we don't drop the old value.
`
``
151
`+
unsafe {
`
``
152
`+
self.0.write(State::Poisoned);
`
``
153
`+
}
`
``
154
`+
}
`
``
155
`+
}
`
``
156
+
``
157
`+
let State::Uninit(f) = state else {
`
``
158
`` +
// unreachable!()
here won't optimize out because the function is cold.
``
``
159
`+
// SAFETY: Precondition.
`
``
160
`+
unsafe { unreachable_unchecked() };
`
``
161
`+
};
`
``
162
`` +
// SAFETY: We never drop the state after we read f
, and we write a valid value back
``
``
163
`` +
// in any case, panic or success. f
can't access the LazyCell
because it is mutably
``
``
164
`+
// borrowed.
`
``
165
`+
let f = unsafe { core::ptr::read(f) };
`
``
166
`+
// INVARIANT: Initiated from mutable reference, don't drop because we read it.
`
``
167
`+
let guard = PoisonOnPanic(state);
`
``
168
`+
let data = f();
`
``
169
`` +
// SAFETY: PoisonOnPanic
invariant, and we don't drop the old value.
``
``
170
`+
unsafe {
`
``
171
`+
core::ptr::write(guard.0, State::Init(data));
`
``
172
`+
}
`
``
173
`+
core::mem::forget(guard);
`
``
174
`+
let State::Init(data) = state else { unreachable!() };
`
``
175
`+
data
`
``
176
`+
}
`
``
177
+
``
178
`+
let state = this.state.get_mut();
`
``
179
`+
match state {
`
``
180
`+
State::Init(data) => data,
`
``
181
`` +
// SAFETY: state
is Uninit
.
``
``
182
`+
State::Uninit(_) => unsafe { really_init_mut(state) },
`
``
183
`+
State::Poisoned => panic_poisoned(),
`
118
184
`}
`
119
185
`}
`
120
186
``
`@@ -152,13 +218,55 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
`
152
218
`}
`
153
219
``
154
220
`impl<T, F> LazyCell<T, F> {
`
``
221
`` +
/// Returns a reference to the value if initialized, or None
if not.
``
``
222
`+
///
`
``
223
`+
/// # Examples
`
``
224
`+
///
`
``
225
/// ```
``
226
`+
/// #![feature(lazy_get)]
`
``
227
`+
///
`
``
228
`+
/// use std::cell::LazyCell;
`
``
229
`+
///
`
``
230
`+
/// let mut lazy = LazyCell::new(|| 92);
`
``
231
`+
///
`
``
232
`+
/// assert_eq!(LazyCell::get_mut(&mut lazy), None);
`
``
233
`+
/// let _ = LazyCell::force(&lazy);
`
``
234
`+
/// *LazyCell::get_mut(&mut lazy).unwrap() = 44;
`
``
235
`+
/// assert_eq!(*lazy, 44);
`
``
236
/// ```
155
237
`#[inline]
`
156
``
`-
fn get(&self) -> Option<&T> {
`
``
238
`+
#[unstable(feature = "lazy_get", issue = "129333")]
`
``
239
`+
pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> {
`
``
240
`+
let state = this.state.get_mut();
`
``
241
`+
match state {
`
``
242
`+
State::Init(data) => Some(data),
`
``
243
`+
_ => None,
`
``
244
`+
}
`
``
245
`+
}
`
``
246
+
``
247
`` +
/// Returns a mutable reference to the value if initialized, or None
if not.
``
``
248
`+
///
`
``
249
`+
/// # Examples
`
``
250
`+
///
`
``
251
/// ```
``
252
`+
/// #![feature(lazy_get)]
`
``
253
`+
///
`
``
254
`+
/// use std::cell::LazyCell;
`
``
255
`+
///
`
``
256
`+
/// let lazy = LazyCell::new(|| 92);
`
``
257
`+
///
`
``
258
`+
/// assert_eq!(LazyCell::get(&lazy), None);
`
``
259
`+
/// let _ = LazyCell::force(&lazy);
`
``
260
`+
/// assert_eq!(LazyCell::get(&lazy), Some(&92));
`
``
261
/// ```
``
262
`+
#[inline]
`
``
263
`+
#[unstable(feature = "lazy_get", issue = "129333")]
`
``
264
`+
pub fn get(this: &LazyCell<T, F>) -> Option<&T> {
`
157
265
`// SAFETY:
`
158
266
`` // This is sound for the same reason as in force
: once the state is
``
159
267
`// initialized, it will not be mutably accessed again, so this reference
`
160
268
`` // will stay valid for the duration of the borrow to self
.
``
161
``
`-
let state = unsafe { &*self.state.get() };
`
``
269
`+
let state = unsafe { &*this.state.get() };
`
162
270
`match state {
`
163
271
`State::Init(data) => Some(data),
`
164
272
` _ => None,
`
`@@ -188,10 +296,16 @@ impl<T: Default> Default for LazyCell {
`
188
296
`impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> {
`
189
297
`fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
`
190
298
`let mut d = f.debug_tuple("LazyCell");
`
191
``
`-
match self.get() {
`
``
299
`+
match LazyCell::get(self) {
`
192
300
`Some(data) => d.field(data),
`
193
301
`None => d.field(&format_args!("")),
`
194
302
`};
`
195
303
` d.finish()
`
196
304
`}
`
197
305
`}
`
``
306
+
``
307
`+
#[cold]
`
``
308
`+
#[inline(never)]
`
``
309
`+
fn panic_poisoned() -> ! {
`
``
310
`+
panic!("LazyCell instance has previously been poisoned")
`
``
311
`+
}
`