Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 01418bd

Browse files
authoredJul 18, 2020
Rollup merge of #72414 - KodrAus:feat/stdlazy, r=Mark-Simulacrum
Add lazy initialization primitives to std Follow-up to #68198 Current RFC: rust-lang/rfcs#2788 Rebased and fixed up a few of the dangling comments. Some notes carried over from the previous PR: - [ ] Naming. I'm ok to just roll with the `Sync` prefix like `SyncLazy` for now, but [have a personal preference for `Atomic`](rust-lang/rfcs#2788 (comment)) like `AtomicLazy`. - [x] [Poisoning](rust-lang/rfcs#2788 (comment)). It seems like there's [some regret around poisoning in other `std::sync` types that we might want to just avoid upfront for `std::lazy`, especially if that would align with a future `std::mutex` that doesn't poison](https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/parking_lot.3A.3AMutex.20in.20std/near/190331199). Personally, if we're adding these types to `std::lazy` instead of `std::sync`, I'd be on-board with not worrying about poisoning in `std::lazy`, and potentially deprecating `std::sync::Once` and `lazy_static` in favour of `std::lazy` down the track if it's possible, rather than attempting to replicate their behavior. cc @Amanieu @sfackler. - [ ] [Consider making`SyncOnceCell::get` blocking](matklad/once_cell#92). There doesn't seem to be consensus in the linked PR on whether or not that's strictly better than the non-blocking variant. In general, none of these seem to be really blocking an initial unstable merge, so we could possibly kick off a FCP if y'all are happy? cc @matklad @pitdicker have I missed anything, or were there any other considerations that have come up since we last looked at this?
2 parents d3df851 + fe63905 commit 01418bd

File tree

7 files changed

+1373
-4
lines changed

7 files changed

+1373
-4
lines changed
 

‎src/libcore/lazy.rs

Lines changed: 379 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,379 @@
1+
//! Lazy values and one-time initialization of static data.
2+
3+
use crate::cell::{Cell, UnsafeCell};
4+
use crate::fmt;
5+
use crate::mem;
6+
use crate::ops::Deref;
7+
8+
/// A cell which can be written to only once.
9+
///
10+
/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value.
11+
/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it.
12+
///
13+
/// # Examples
14+
///
15+
/// ```
16+
/// #![feature(once_cell)]
17+
///
18+
/// use std::lazy::OnceCell;
19+
///
20+
/// let cell = OnceCell::new();
21+
/// assert!(cell.get().is_none());
22+
///
23+
/// let value: &String = cell.get_or_init(|| {
24+
/// "Hello, World!".to_string()
25+
/// });
26+
/// assert_eq!(value, "Hello, World!");
27+
/// assert!(cell.get().is_some());
28+
/// ```
29+
#[unstable(feature = "once_cell", issue = "74465")]
30+
pub struct OnceCell<T> {
31+
// Invariant: written to at most once.
32+
inner: UnsafeCell<Option<T>>,
33+
}
34+
35+
#[unstable(feature = "once_cell", issue = "74465")]
36+
impl<T> Default for OnceCell<T> {
37+
fn default() -> Self {
38+
Self::new()
39+
}
40+
}
41+
42+
#[unstable(feature = "once_cell", issue = "74465")]
43+
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
44+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45+
match self.get() {
46+
Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
47+
None => f.write_str("OnceCell(Uninit)"),
48+
}
49+
}
50+
}
51+
52+
#[unstable(feature = "once_cell", issue = "74465")]
53+
impl<T: Clone> Clone for OnceCell<T> {
54+
fn clone(&self) -> OnceCell<T> {
55+
let res = OnceCell::new();
56+
if let Some(value) = self.get() {
57+
match res.set(value.clone()) {
58+
Ok(()) => (),
59+
Err(_) => unreachable!(),
60+
}
61+
}
62+
res
63+
}
64+
}
65+
66+
#[unstable(feature = "once_cell", issue = "74465")]
67+
impl<T: PartialEq> PartialEq for OnceCell<T> {
68+
fn eq(&self, other: &Self) -> bool {
69+
self.get() == other.get()
70+
}
71+
}
72+
73+
#[unstable(feature = "once_cell", issue = "74465")]
74+
impl<T: Eq> Eq for OnceCell<T> {}
75+
76+
#[unstable(feature = "once_cell", issue = "74465")]
77+
impl<T> From<T> for OnceCell<T> {
78+
fn from(value: T) -> Self {
79+
OnceCell { inner: UnsafeCell::new(Some(value)) }
80+
}
81+
}
82+
83+
impl<T> OnceCell<T> {
84+
/// Creates a new empty cell.
85+
#[unstable(feature = "once_cell", issue = "74465")]
86+
pub const fn new() -> OnceCell<T> {
87+
OnceCell { inner: UnsafeCell::new(None) }
88+
}
89+
90+
/// Gets the reference to the underlying value.
91+
///
92+
/// Returns `None` if the cell is empty.
93+
#[unstable(feature = "once_cell", issue = "74465")]
94+
pub fn get(&self) -> Option<&T> {
95+
// Safety: Safe due to `inner`'s invariant
96+
unsafe { &*self.inner.get() }.as_ref()
97+
}
98+
99+
/// Gets the mutable reference to the underlying value.
100+
///
101+
/// Returns `None` if the cell is empty.
102+
#[unstable(feature = "once_cell", issue = "74465")]
103+
pub fn get_mut(&mut self) -> Option<&mut T> {
104+
// Safety: Safe because we have unique access
105+
unsafe { &mut *self.inner.get() }.as_mut()
106+
}
107+
108+
/// Sets the contents of the cell to `value`.
109+
///
110+
/// # Errors
111+
///
112+
/// This method returns `Ok(())` if the cell was empty and `Err(value)` if
113+
/// it was full.
114+
///
115+
/// # Examples
116+
///
117+
/// ```
118+
/// #![feature(once_cell)]
119+
///
120+
/// use std::lazy::OnceCell;
121+
///
122+
/// let cell = OnceCell::new();
123+
/// assert!(cell.get().is_none());
124+
///
125+
/// assert_eq!(cell.set(92), Ok(()));
126+
/// assert_eq!(cell.set(62), Err(62));
127+
///
128+
/// assert!(cell.get().is_some());
129+
/// ```
130+
#[unstable(feature = "once_cell", issue = "74465")]
131+
pub fn set(&self, value: T) -> Result<(), T> {
132+
// Safety: Safe because we cannot have overlapping mutable borrows
133+
let slot = unsafe { &*self.inner.get() };
134+
if slot.is_some() {
135+
return Err(value);
136+
}
137+
138+
// Safety: This is the only place where we set the slot, no races
139+
// due to reentrancy/concurrency are possible, and we've
140+
// checked that slot is currently `None`, so this write
141+
// maintains the `inner`'s invariant.
142+
let slot = unsafe { &mut *self.inner.get() };
143+
*slot = Some(value);
144+
Ok(())
145+
}
146+
147+
/// Gets the contents of the cell, initializing it with `f`
148+
/// if the cell was empty.
149+
///
150+
/// # Panics
151+
///
152+
/// If `f` panics, the panic is propagated to the caller, and the cell
153+
/// remains uninitialized.
154+
///
155+
/// It is an error to reentrantly initialize the cell from `f`. Doing
156+
/// so results in a panic.
157+
///
158+
/// # Examples
159+
///
160+
/// ```
161+
/// #![feature(once_cell)]
162+
///
163+
/// use std::lazy::OnceCell;
164+
///
165+
/// let cell = OnceCell::new();
166+
/// let value = cell.get_or_init(|| 92);
167+
/// assert_eq!(value, &92);
168+
/// let value = cell.get_or_init(|| unreachable!());
169+
/// assert_eq!(value, &92);
170+
/// ```
171+
#[unstable(feature = "once_cell", issue = "74465")]
172+
pub fn get_or_init<F>(&self, f: F) -> &T
173+
where
174+
F: FnOnce() -> T,
175+
{
176+
match self.get_or_try_init(|| Ok::<T, !>(f())) {
177+
Ok(val) => val,
178+
}
179+
}
180+
181+
/// Gets the contents of the cell, initializing it with `f` if
182+
/// the cell was empty. If the cell was empty and `f` failed, an
183+
/// error is returned.
184+
///
185+
/// # Panics
186+
///
187+
/// If `f` panics, the panic is propagated to the caller, and the cell
188+
/// remains uninitialized.
189+
///
190+
/// It is an error to reentrantly initialize the cell from `f`. Doing
191+
/// so results in a panic.
192+
///
193+
/// # Examples
194+
///
195+
/// ```
196+
/// #![feature(once_cell)]
197+
///
198+
/// use std::lazy::OnceCell;
199+
///
200+
/// let cell = OnceCell::new();
201+
/// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
202+
/// assert!(cell.get().is_none());
203+
/// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
204+
/// Ok(92)
205+
/// });
206+
/// assert_eq!(value, Ok(&92));
207+
/// assert_eq!(cell.get(), Some(&92))
208+
/// ```
209+
#[unstable(feature = "once_cell", issue = "74465")]
210+
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
211+
where
212+
F: FnOnce() -> Result<T, E>,
213+
{
214+
if let Some(val) = self.get() {
215+
return Ok(val);
216+
}
217+
let val = f()?;
218+
// Note that *some* forms of reentrant initialization might lead to
219+
// UB (see `reentrant_init` test). I believe that just removing this
220+
// `assert`, while keeping `set/get` would be sound, but it seems
221+
// better to panic, rather than to silently use an old value.
222+
assert!(self.set(val).is_ok(), "reentrant init");
223+
Ok(self.get().unwrap())
224+
}
225+
226+
/// Consumes the cell, returning the wrapped value.
227+
///
228+
/// Returns `None` if the cell was empty.
229+
///
230+
/// # Examples
231+
///
232+
/// ```
233+
/// #![feature(once_cell)]
234+
///
235+
/// use std::lazy::OnceCell;
236+
///
237+
/// let cell: OnceCell<String> = OnceCell::new();
238+
/// assert_eq!(cell.into_inner(), None);
239+
///
240+
/// let cell = OnceCell::new();
241+
/// cell.set("hello".to_string()).unwrap();
242+
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
243+
/// ```
244+
#[unstable(feature = "once_cell", issue = "74465")]
245+
pub fn into_inner(self) -> Option<T> {
246+
// Because `into_inner` takes `self` by value, the compiler statically verifies
247+
// that it is not currently borrowed. So it is safe to move out `Option<T>`.
248+
self.inner.into_inner()
249+
}
250+
251+
/// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
252+
///
253+
/// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
254+
///
255+
/// Safety is guaranteed by requiring a mutable reference.
256+
///
257+
/// # Examples
258+
///
259+
/// ```
260+
/// #![feature(once_cell)]
261+
///
262+
/// use std::lazy::OnceCell;
263+
///
264+
/// let mut cell: OnceCell<String> = OnceCell::new();
265+
/// assert_eq!(cell.take(), None);
266+
///
267+
/// let mut cell = OnceCell::new();
268+
/// cell.set("hello".to_string()).unwrap();
269+
/// assert_eq!(cell.take(), Some("hello".to_string()));
270+
/// assert_eq!(cell.get(), None);
271+
/// ```
272+
#[unstable(feature = "once_cell", issue = "74465")]
273+
pub fn take(&mut self) -> Option<T> {
274+
mem::take(self).into_inner()
275+
}
276+
}
277+
278+
/// A value which is initialized on the first access.
279+
///
280+
/// # Examples
281+
///
282+
/// ```
283+
/// #![feature(once_cell)]
284+
///
285+
/// use std::lazy::Lazy;
286+
///
287+
/// let lazy: Lazy<i32> = Lazy::new(|| {
288+
/// println!("initializing");
289+
/// 92
290+
/// });
291+
/// println!("ready");
292+
/// println!("{}", *lazy);
293+
/// println!("{}", *lazy);
294+
///
295+
/// // Prints:
296+
/// // ready
297+
/// // initializing
298+
/// // 92
299+
/// // 92
300+
/// ```
301+
#[unstable(feature = "once_cell", issue = "74465")]
302+
pub struct Lazy<T, F = fn() -> T> {
303+
cell: OnceCell<T>,
304+
init: Cell<Option<F>>,
305+
}
306+
307+
#[unstable(feature = "once_cell", issue = "74465")]
308+
impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
309+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310+
f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
311+
}
312+
}
313+
314+
impl<T, F> Lazy<T, F> {
315+
/// Creates a new lazy value with the given initializing function.
316+
///
317+
/// # Examples
318+
///
319+
/// ```
320+
/// #![feature(once_cell)]
321+
///
322+
/// # fn main() {
323+
/// use std::lazy::Lazy;
324+
///
325+
/// let hello = "Hello, World!".to_string();
326+
///
327+
/// let lazy = Lazy::new(|| hello.to_uppercase());
328+
///
329+
/// assert_eq!(&*lazy, "HELLO, WORLD!");
330+
/// # }
331+
/// ```
332+
#[unstable(feature = "once_cell", issue = "74465")]
333+
pub const fn new(init: F) -> Lazy<T, F> {
334+
Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) }
335+
}
336+
}
337+
338+
impl<T, F: FnOnce() -> T> Lazy<T, F> {
339+
/// Forces the evaluation of this lazy value and returns a reference to
340+
/// the result.
341+
///
342+
/// This is equivalent to the `Deref` impl, but is explicit.
343+
///
344+
/// # Examples
345+
///
346+
/// ```
347+
/// #![feature(once_cell)]
348+
///
349+
/// use std::lazy::Lazy;
350+
///
351+
/// let lazy = Lazy::new(|| 92);
352+
///
353+
/// assert_eq!(Lazy::force(&lazy), &92);
354+
/// assert_eq!(&*lazy, &92);
355+
/// ```
356+
#[unstable(feature = "once_cell", issue = "74465")]
357+
pub fn force(this: &Lazy<T, F>) -> &T {
358+
this.cell.get_or_init(|| match this.init.take() {
359+
Some(f) => f(),
360+
None => panic!("`Lazy` instance has previously been poisoned"),
361+
})
362+
}
363+
}
364+
365+
#[unstable(feature = "once_cell", issue = "74465")]
366+
impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
367+
type Target = T;
368+
fn deref(&self) -> &T {
369+
Lazy::force(self)
370+
}
371+
}
372+
373+
#[unstable(feature = "once_cell", issue = "74465")]
374+
impl<T: Default> Default for Lazy<T> {
375+
/// Creates a new lazy value using `Default` as the initializing function.
376+
fn default() -> Lazy<T> {
377+
Lazy::new(T::default)
378+
}
379+
}

‎src/libcore/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ pub mod char;
239239
pub mod ffi;
240240
#[cfg(not(test))] // See #65860
241241
pub mod iter;
242+
#[unstable(feature = "once_cell", issue = "74465")]
243+
pub mod lazy;
242244
pub mod option;
243245
pub mod panic;
244246
pub mod panicking;

‎src/libcore/tests/lazy.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use core::{
2+
cell::Cell,
3+
lazy::{Lazy, OnceCell},
4+
sync::atomic::{AtomicUsize, Ordering::SeqCst},
5+
};
6+
7+
#[test]
8+
fn once_cell() {
9+
let c = OnceCell::new();
10+
assert!(c.get().is_none());
11+
c.get_or_init(|| 92);
12+
assert_eq!(c.get(), Some(&92));
13+
14+
c.get_or_init(|| panic!("Kabom!"));
15+
assert_eq!(c.get(), Some(&92));
16+
}
17+
18+
#[test]
19+
fn once_cell_get_mut() {
20+
let mut c = OnceCell::new();
21+
assert!(c.get_mut().is_none());
22+
c.set(90).unwrap();
23+
*c.get_mut().unwrap() += 2;
24+
assert_eq!(c.get_mut(), Some(&mut 92));
25+
}
26+
27+
#[test]
28+
fn once_cell_drop() {
29+
static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
30+
struct Dropper;
31+
impl Drop for Dropper {
32+
fn drop(&mut self) {
33+
DROP_CNT.fetch_add(1, SeqCst);
34+
}
35+
}
36+
37+
let x = OnceCell::new();
38+
x.get_or_init(|| Dropper);
39+
assert_eq!(DROP_CNT.load(SeqCst), 0);
40+
drop(x);
41+
assert_eq!(DROP_CNT.load(SeqCst), 1);
42+
}
43+
44+
#[test]
45+
fn unsync_once_cell_drop_empty() {
46+
let x = OnceCell::<&'static str>::new();
47+
drop(x);
48+
}
49+
50+
#[test]
51+
fn clone() {
52+
let s = OnceCell::new();
53+
let c = s.clone();
54+
assert!(c.get().is_none());
55+
56+
s.set("hello").unwrap();
57+
let c = s.clone();
58+
assert_eq!(c.get().map(|c| *c), Some("hello"));
59+
}
60+
61+
#[test]
62+
fn from_impl() {
63+
assert_eq!(OnceCell::from("value").get(), Some(&"value"));
64+
assert_ne!(OnceCell::from("foo").get(), Some(&"bar"));
65+
}
66+
67+
#[test]
68+
fn partialeq_impl() {
69+
assert!(OnceCell::from("value") == OnceCell::from("value"));
70+
assert!(OnceCell::from("foo") != OnceCell::from("bar"));
71+
72+
assert!(OnceCell::<&'static str>::new() == OnceCell::new());
73+
assert!(OnceCell::<&'static str>::new() != OnceCell::from("value"));
74+
}
75+
76+
#[test]
77+
fn into_inner() {
78+
let cell: OnceCell<&'static str> = OnceCell::new();
79+
assert_eq!(cell.into_inner(), None);
80+
let cell = OnceCell::new();
81+
cell.set("hello").unwrap();
82+
assert_eq!(cell.into_inner(), Some("hello"));
83+
}
84+
85+
#[test]
86+
fn lazy_new() {
87+
let called = Cell::new(0);
88+
let x = Lazy::new(|| {
89+
called.set(called.get() + 1);
90+
92
91+
});
92+
93+
assert_eq!(called.get(), 0);
94+
95+
let y = *x - 30;
96+
assert_eq!(y, 62);
97+
assert_eq!(called.get(), 1);
98+
99+
let y = *x - 30;
100+
assert_eq!(y, 62);
101+
assert_eq!(called.get(), 1);
102+
}
103+
104+
#[test]
105+
fn aliasing_in_get() {
106+
let x = OnceCell::new();
107+
x.set(42).unwrap();
108+
let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
109+
let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>` |
110+
println!("{}", at_x); // <------- up until here ---------------------------+
111+
}
112+
113+
#[test]
114+
#[should_panic(expected = "reentrant init")]
115+
fn reentrant_init() {
116+
let x: OnceCell<Box<i32>> = OnceCell::new();
117+
let dangling_ref: Cell<Option<&i32>> = Cell::new(None);
118+
x.get_or_init(|| {
119+
let r = x.get_or_init(|| Box::new(92));
120+
dangling_ref.set(Some(r));
121+
Box::new(62)
122+
});
123+
eprintln!("use after free: {:?}", dangling_ref.get().unwrap());
124+
}

‎src/libcore/tests/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#![feature(option_unwrap_none)]
4444
#![feature(peekable_next_if)]
4545
#![feature(partition_point)]
46+
#![feature(once_cell)]
4647
#![feature(unsafe_block_in_unsafe_fn)]
4748
#![deny(unsafe_op_in_unsafe_fn)]
4849

@@ -62,6 +63,7 @@ mod fmt;
6263
mod hash;
6364
mod intrinsics;
6465
mod iter;
66+
mod lazy;
6567
mod manually_drop;
6668
mod mem;
6769
mod nonzero;

‎src/libstd/lazy.rs

Lines changed: 844 additions & 0 deletions
Large diffs are not rendered by default.

‎src/libstd/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,15 @@
287287
#![feature(linkage)]
288288
#![feature(llvm_asm)]
289289
#![feature(log_syntax)]
290+
#![feature(maybe_uninit_extra)]
290291
#![feature(maybe_uninit_ref)]
291292
#![feature(maybe_uninit_slice)]
292293
#![feature(min_specialization)]
293294
#![feature(needs_panic_runtime)]
294295
#![feature(negative_impls)]
295296
#![feature(never_type)]
296297
#![feature(nll)]
298+
#![feature(once_cell)]
297299
#![feature(optin_builtin_traits)]
298300
#![feature(or_patterns)]
299301
#![feature(panic_info_message)]
@@ -477,6 +479,9 @@ pub mod process;
477479
pub mod sync;
478480
pub mod time;
479481

482+
#[unstable(feature = "once_cell", issue = "74465")]
483+
pub mod lazy;
484+
480485
#[stable(feature = "futures_api", since = "1.36.0")]
481486
pub mod task {
482487
//! Types and Traits for working with asynchronous tasks.

‎src/libstd/sync/once.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ unsafe impl Send for Once {}
132132
#[derive(Debug)]
133133
pub struct OnceState {
134134
poisoned: bool,
135+
set_state_on_drop_to: Cell<usize>,
135136
}
136137

137138
/// Initialization value for static [`Once`] values.
@@ -321,7 +322,7 @@ impl Once {
321322
}
322323

323324
let mut f = Some(f);
324-
self.call_inner(true, &mut |p| f.take().unwrap()(&OnceState { poisoned: p }));
325+
self.call_inner(true, &mut |p| f.take().unwrap()(p));
325326
}
326327

327328
/// Returns `true` if some `call_once` call has completed
@@ -385,7 +386,7 @@ impl Once {
385386
// currently no way to take an `FnOnce` and call it via virtual dispatch
386387
// without some allocation overhead.
387388
#[cold]
388-
fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(bool)) {
389+
fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) {
389390
let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire);
390391
loop {
391392
match state_and_queue {
@@ -413,8 +414,12 @@ impl Once {
413414
};
414415
// Run the initialization function, letting it know if we're
415416
// poisoned or not.
416-
init(state_and_queue == POISONED);
417-
waiter_queue.set_state_on_drop_to = COMPLETE;
417+
let init_state = OnceState {
418+
poisoned: state_and_queue == POISONED,
419+
set_state_on_drop_to: Cell::new(COMPLETE),
420+
};
421+
init(&init_state);
422+
waiter_queue.set_state_on_drop_to = init_state.set_state_on_drop_to.get();
418423
break;
419424
}
420425
_ => {
@@ -554,6 +559,14 @@ impl OnceState {
554559
pub fn poisoned(&self) -> bool {
555560
self.poisoned
556561
}
562+
563+
/// Poison the associated [`Once`] without explicitly panicking.
564+
///
565+
/// [`Once`]: struct.Once.html
566+
// NOTE: This is currently only exposed for the `lazy` module
567+
pub(crate) fn poison(&self) {
568+
self.set_state_on_drop_to.set(POISONED);
569+
}
557570
}
558571

559572
#[cfg(all(test, not(target_os = "emscripten")))]

0 commit comments

Comments
 (0)
Please sign in to comment.