Rollup merge of #98165 - WaffleLapkin:once_things_renamings, r=m-ou-se
once cell renamings This PR does the renamings proposed in https://github.com/rust-lang/rust/issues/74465#issuecomment-1153703128 - Move/rename `lazy::{OnceCell, Lazy}` to `cell::{OnceCell, LazyCell}` - Move/rename `lazy::{SyncOnceCell, SyncLazy}` to `sync::{OnceLock, LazyLock}` (I used `Lazy...` instead of `...Lazy` as it seems to be more consistent, easier to pronounce, etc) ```@rustbot``` label +T-libs-api -T-libs
This commit is contained in:
commit
f351f347b8
40 changed files with 1250 additions and 1215 deletions
|
@ -13,7 +13,7 @@ use rustc_span::Symbol;
|
||||||
|
|
||||||
use cranelift_jit::{JITBuilder, JITModule};
|
use cranelift_jit::{JITBuilder, JITModule};
|
||||||
|
|
||||||
// FIXME use std::lazy::SyncOnceCell once it stabilizes
|
// FIXME use std::sync::OnceLock once it stabilizes
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
use crate::{prelude::*, BackendConfig};
|
use crate::{prelude::*, BackendConfig};
|
||||||
|
|
|
@ -36,9 +36,9 @@ use rustc_target::abi::Size;
|
||||||
|
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
use std::cell::OnceCell;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::lazy::OnceCell;
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
mod create_scope_map;
|
mod create_scope_map;
|
||||||
|
|
|
@ -38,11 +38,11 @@ use regex::Regex;
|
||||||
use tempfile::Builder as TempFileBuilder;
|
use tempfile::Builder as TempFileBuilder;
|
||||||
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
use std::cell::OnceCell;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
use std::lazy::OnceCell;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{ExitStatus, Output, Stdio};
|
use std::process::{ExitStatus, Output, Stdio};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub use jobserver_crate::Client;
|
pub use jobserver_crate::Client;
|
||||||
use std::lazy::SyncLazy;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
// We can only call `from_env` once per process
|
// We can only call `from_env` once per process
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ use std::lazy::SyncLazy;
|
||||||
// Also note that we stick this in a global because there could be
|
// Also note that we stick this in a global because there could be
|
||||||
// multiple rustc instances in this process, and the jobserver is
|
// multiple rustc instances in this process, and the jobserver is
|
||||||
// per-process.
|
// per-process.
|
||||||
static GLOBAL_CLIENT: SyncLazy<Client> = SyncLazy::new(|| unsafe {
|
static GLOBAL_CLIENT: LazyLock<Client> = LazyLock::new(|| unsafe {
|
||||||
Client::from_env().unwrap_or_else(|| {
|
Client::from_env().unwrap_or_else(|| {
|
||||||
let client = Client::new(32).expect("failed to create jobserver");
|
let client = Client::new(32).expect("failed to create jobserver");
|
||||||
// Acquire a token for the main thread which we can release later
|
// Acquire a token for the main thread which we can release later
|
||||||
|
|
|
@ -173,7 +173,7 @@ cfg_if! {
|
||||||
pub use std::cell::RefMut as LockGuard;
|
pub use std::cell::RefMut as LockGuard;
|
||||||
pub use std::cell::RefMut as MappedLockGuard;
|
pub use std::cell::RefMut as MappedLockGuard;
|
||||||
|
|
||||||
pub use std::lazy::OnceCell;
|
pub use std::cell::OnceCell;
|
||||||
|
|
||||||
use std::cell::RefCell as InnerRwLock;
|
use std::cell::RefCell as InnerRwLock;
|
||||||
use std::cell::RefCell as InnerLock;
|
use std::cell::RefCell as InnerLock;
|
||||||
|
@ -258,7 +258,7 @@ cfg_if! {
|
||||||
pub use parking_lot::MutexGuard as LockGuard;
|
pub use parking_lot::MutexGuard as LockGuard;
|
||||||
pub use parking_lot::MappedMutexGuard as MappedLockGuard;
|
pub use parking_lot::MappedMutexGuard as MappedLockGuard;
|
||||||
|
|
||||||
pub use std::lazy::SyncOnceCell as OnceCell;
|
pub use std::sync::OnceLock as OnceCell;
|
||||||
|
|
||||||
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
|
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
|
||||||
|
|
||||||
|
|
|
@ -47,11 +47,11 @@ use std::env;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::lazy::SyncLazy;
|
|
||||||
use std::panic::{self, catch_unwind};
|
use std::panic::{self, catch_unwind};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::{self, Command, Stdio};
|
use std::process::{self, Command, Stdio};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::sync::LazyLock;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
pub mod args;
|
pub mod args;
|
||||||
|
@ -1141,8 +1141,8 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFAULT_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
|
static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
|
||||||
SyncLazy::new(|| {
|
LazyLock::new(|| {
|
||||||
let hook = panic::take_hook();
|
let hook = panic::take_hook();
|
||||||
panic::set_hook(Box::new(|info| {
|
panic::set_hook(Box::new(|info| {
|
||||||
// Invoke the default handler, which prints the actual panic message and optionally a backtrace
|
// Invoke the default handler, which prints the actual panic message and optionally a backtrace
|
||||||
|
@ -1237,7 +1237,7 @@ pub fn install_ice_hook() {
|
||||||
if std::env::var("RUST_BACKTRACE").is_err() {
|
if std::env::var("RUST_BACKTRACE").is_err() {
|
||||||
std::env::set_var("RUST_BACKTRACE", "full");
|
std::env::set_var("RUST_BACKTRACE", "full");
|
||||||
}
|
}
|
||||||
SyncLazy::force(&DEFAULT_HOOK);
|
LazyLock::force(&DEFAULT_HOOK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This allows tools to enable rust logging without having to magically match rustc's
|
/// This allows tools to enable rust logging without having to magically match rustc's
|
||||||
|
|
|
@ -18,9 +18,9 @@ use std::path::{Path, PathBuf};
|
||||||
use tracing::{instrument, trace};
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
#[cfg(not(parallel_compiler))]
|
#[cfg(not(parallel_compiler))]
|
||||||
use std::lazy::Lazy;
|
use std::cell::LazyCell as Lazy;
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
use std::lazy::SyncLazy as Lazy;
|
use std::sync::LazyLock as Lazy;
|
||||||
|
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
use intl_memoizer::concurrent::IntlLangMemoizer;
|
use intl_memoizer::concurrent::IntlLangMemoizer;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{Features, Stability};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
|
||||||
use std::lazy::SyncLazy;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
type GateFn = fn(&Features) -> bool;
|
type GateFn = fn(&Features) -> bool;
|
||||||
|
|
||||||
|
@ -809,8 +809,8 @@ pub fn is_builtin_only_local(name: Symbol) -> bool {
|
||||||
BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
|
BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> =
|
pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
|
||||||
SyncLazy::new(|| {
|
LazyLock::new(|| {
|
||||||
let mut map = FxHashMap::default();
|
let mut map = FxHashMap::default();
|
||||||
for attr in BUILTIN_ATTRIBUTES.iter() {
|
for attr in BUILTIN_ATTRIBUTES.iter() {
|
||||||
if map.insert(attr.name, attr).is_some() {
|
if map.insert(attr.name, attr).is_some() {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use rustc_macros::HashStable_Generic;
|
||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use std::lazy::SyncLazy;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub enum LangItemGroup {
|
pub enum LangItemGroup {
|
||||||
Op,
|
Op,
|
||||||
|
@ -134,7 +134,7 @@ macro_rules! language_item_table {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mapping from the name of the lang item to its order and the form it must be of.
|
/// A mapping from the name of the lang item to its order and the form it must be of.
|
||||||
pub static ITEM_REFS: SyncLazy<FxHashMap<Symbol, (usize, Target)>> = SyncLazy::new(|| {
|
pub static ITEM_REFS: LazyLock<FxHashMap<Symbol, (usize, Target)>> = LazyLock::new(|| {
|
||||||
let mut item_refs = FxHashMap::default();
|
let mut item_refs = FxHashMap::default();
|
||||||
$( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )*
|
$( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )*
|
||||||
item_refs
|
item_refs
|
||||||
|
|
|
@ -7,12 +7,12 @@ use rustc_ast as ast;
|
||||||
use rustc_data_structures::stable_map::StableMap;
|
use rustc_data_structures::stable_map::StableMap;
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
|
||||||
use std::lazy::SyncLazy;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
macro_rules! weak_lang_items {
|
macro_rules! weak_lang_items {
|
||||||
($($name:ident, $item:ident, $sym:ident;)*) => (
|
($($name:ident, $item:ident, $sym:ident;)*) => (
|
||||||
|
|
||||||
pub static WEAK_ITEMS_REFS: SyncLazy<StableMap<Symbol, LangItem>> = SyncLazy::new(|| {
|
pub static WEAK_ITEMS_REFS: LazyLock<StableMap<Symbol, LangItem>> = LazyLock::new(|| {
|
||||||
let mut map = StableMap::default();
|
let mut map = StableMap::default();
|
||||||
$(map.insert(sym::$name, LangItem::$item);)*
|
$(map.insert(sym::$name, LangItem::$item);)*
|
||||||
map
|
map
|
||||||
|
|
|
@ -44,11 +44,11 @@ use std::any::Any;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::io::{self, BufWriter, Write};
|
use std::io::{self, BufWriter, Write};
|
||||||
use std::lazy::SyncLazy;
|
|
||||||
use std::marker::PhantomPinned;
|
use std::marker::PhantomPinned;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::LazyLock;
|
||||||
use std::{env, fs, iter};
|
use std::{env, fs, iter};
|
||||||
|
|
||||||
pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
|
pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
|
||||||
|
@ -774,7 +774,7 @@ pub fn prepare_outputs(
|
||||||
Ok(outputs)
|
Ok(outputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static DEFAULT_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| {
|
pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
|
||||||
let providers = &mut Providers::default();
|
let providers = &mut Providers::default();
|
||||||
providers.analysis = analysis;
|
providers.analysis = analysis;
|
||||||
proc_macro_decls::provide(providers);
|
proc_macro_decls::provide(providers);
|
||||||
|
@ -799,7 +799,7 @@ pub static DEFAULT_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| {
|
||||||
*providers
|
*providers
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<ExternProviders> = SyncLazy::new(|| {
|
pub static DEFAULT_EXTERN_QUERY_PROVIDERS: LazyLock<ExternProviders> = LazyLock::new(|| {
|
||||||
let mut extern_providers = ExternProviders::default();
|
let mut extern_providers = ExternProviders::default();
|
||||||
rustc_metadata::provide_extern(&mut extern_providers);
|
rustc_metadata::provide_extern(&mut extern_providers);
|
||||||
rustc_codegen_ssa::provide_extern(&mut extern_providers);
|
rustc_codegen_ssa::provide_extern(&mut extern_providers);
|
||||||
|
|
|
@ -24,12 +24,12 @@ use rustc_span::source_map::FileLoader;
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||||
use std::lazy::SyncOnceCell;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
#[cfg(not(parallel_compiler))]
|
#[cfg(not(parallel_compiler))]
|
||||||
use std::panic;
|
use std::panic;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::OnceLock;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ pub fn get_codegen_backend(
|
||||||
maybe_sysroot: &Option<PathBuf>,
|
maybe_sysroot: &Option<PathBuf>,
|
||||||
backend_name: Option<&str>,
|
backend_name: Option<&str>,
|
||||||
) -> Box<dyn CodegenBackend> {
|
) -> Box<dyn CodegenBackend> {
|
||||||
static LOAD: SyncOnceCell<unsafe fn() -> Box<dyn CodegenBackend>> = SyncOnceCell::new();
|
static LOAD: OnceLock<unsafe fn() -> Box<dyn CodegenBackend>> = OnceLock::new();
|
||||||
|
|
||||||
let load = LOAD.get_or_init(|| {
|
let load = LOAD.get_or_init(|| {
|
||||||
let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm");
|
let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm");
|
||||||
|
@ -265,7 +265,7 @@ pub fn get_codegen_backend(
|
||||||
// loading, so we leave the code here. It is potentially useful for other tools
|
// loading, so we leave the code here. It is potentially useful for other tools
|
||||||
// that want to invoke the rustc binary while linking to rustc as well.
|
// that want to invoke the rustc binary while linking to rustc as well.
|
||||||
pub fn rustc_path<'a>() -> Option<&'a Path> {
|
pub fn rustc_path<'a>() -> Option<&'a Path> {
|
||||||
static RUSTC_PATH: SyncOnceCell<Option<PathBuf>> = SyncOnceCell::new();
|
static RUSTC_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
|
||||||
|
|
||||||
const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR");
|
const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR");
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! A helpful diagram for debugging dataflow problems.
|
//! A helpful diagram for debugging dataflow problems.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::lazy::SyncOnceCell;
|
use std::sync::OnceLock;
|
||||||
use std::{io, ops, str};
|
use std::{io, ops, str};
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -590,7 +590,7 @@ where
|
||||||
|
|
||||||
macro_rules! regex {
|
macro_rules! regex {
|
||||||
($re:literal $(,)?) => {{
|
($re:literal $(,)?) => {{
|
||||||
static RE: SyncOnceCell<regex::Regex> = SyncOnceCell::new();
|
static RE: OnceLock<regex::Regex> = OnceLock::new();
|
||||||
RE.get_or_init(|| Regex::new($re).unwrap())
|
RE.get_or_init(|| Regex::new($re).unwrap())
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,15 +123,15 @@ use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::lazy::SyncOnceCell;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
pub const NESTED_INDENT: &str = " ";
|
pub const NESTED_INDENT: &str = " ";
|
||||||
|
|
||||||
const RUSTC_COVERAGE_DEBUG_OPTIONS: &str = "RUSTC_COVERAGE_DEBUG_OPTIONS";
|
const RUSTC_COVERAGE_DEBUG_OPTIONS: &str = "RUSTC_COVERAGE_DEBUG_OPTIONS";
|
||||||
|
|
||||||
pub(super) fn debug_options<'a>() -> &'a DebugOptions {
|
pub(super) fn debug_options<'a>() -> &'a DebugOptions {
|
||||||
static DEBUG_OPTIONS: SyncOnceCell<DebugOptions> = SyncOnceCell::new();
|
static DEBUG_OPTIONS: OnceLock<DebugOptions> = OnceLock::new();
|
||||||
|
|
||||||
&DEBUG_OPTIONS.get_or_init(DebugOptions::from_env)
|
&DEBUG_OPTIONS.get_or_init(DebugOptions::from_env)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,9 @@ use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
|
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
|
||||||
|
|
||||||
|
use std::cell::LazyCell;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::lazy::Lazy;
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
/// Helper type of a temporary returned by `.for_item(...)`.
|
/// Helper type of a temporary returned by `.for_item(...)`.
|
||||||
|
@ -1728,7 +1728,7 @@ fn check_variances_for_type_defn<'tcx>(
|
||||||
identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters);
|
identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters);
|
||||||
|
|
||||||
// Lazily calculated because it is only needed in case of an error.
|
// Lazily calculated because it is only needed in case of an error.
|
||||||
let explicitly_bounded_params = Lazy::new(|| {
|
let explicitly_bounded_params = LazyCell::new(|| {
|
||||||
let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
|
let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
|
||||||
hir_generics
|
hir_generics
|
||||||
.predicates
|
.predicates
|
||||||
|
|
|
@ -199,6 +199,14 @@ use crate::mem;
|
||||||
use crate::ops::{CoerceUnsized, Deref, DerefMut};
|
use crate::ops::{CoerceUnsized, Deref, DerefMut};
|
||||||
use crate::ptr::{self, NonNull};
|
use crate::ptr::{self, NonNull};
|
||||||
|
|
||||||
|
mod lazy;
|
||||||
|
mod once;
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub use lazy::LazyCell;
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub use once::OnceCell;
|
||||||
|
|
||||||
/// A mutable memory location.
|
/// A mutable memory location.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
104
library/core/src/cell/lazy.rs
Normal file
104
library/core/src/cell/lazy.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
use crate::cell::{Cell, OnceCell};
|
||||||
|
use crate::fmt;
|
||||||
|
use crate::ops::Deref;
|
||||||
|
|
||||||
|
/// A value which is initialized on the first access.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::LazyCell;
|
||||||
|
///
|
||||||
|
/// let lazy: LazyCell<i32> = LazyCell::new(|| {
|
||||||
|
/// println!("initializing");
|
||||||
|
/// 92
|
||||||
|
/// });
|
||||||
|
/// println!("ready");
|
||||||
|
/// println!("{}", *lazy);
|
||||||
|
/// println!("{}", *lazy);
|
||||||
|
///
|
||||||
|
/// // Prints:
|
||||||
|
/// // ready
|
||||||
|
/// // initializing
|
||||||
|
/// // 92
|
||||||
|
/// // 92
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub struct LazyCell<T, F = fn() -> T> {
|
||||||
|
cell: OnceCell<T>,
|
||||||
|
init: Cell<Option<F>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F> LazyCell<T, F> {
|
||||||
|
/// Creates a new lazy value with the given initializing function.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::LazyCell;
|
||||||
|
///
|
||||||
|
/// let hello = "Hello, World!".to_string();
|
||||||
|
///
|
||||||
|
/// let lazy = LazyCell::new(|| hello.to_uppercase());
|
||||||
|
///
|
||||||
|
/// assert_eq!(&*lazy, "HELLO, WORLD!");
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub const fn new(init: F) -> LazyCell<T, F> {
|
||||||
|
LazyCell { cell: OnceCell::new(), init: Cell::new(Some(init)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: FnOnce() -> T> LazyCell<T, F> {
|
||||||
|
/// Forces the evaluation of this lazy value and returns a reference to
|
||||||
|
/// the result.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the `Deref` impl, but is explicit.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::LazyCell;
|
||||||
|
///
|
||||||
|
/// let lazy = LazyCell::new(|| 92);
|
||||||
|
///
|
||||||
|
/// assert_eq!(LazyCell::force(&lazy), &92);
|
||||||
|
/// assert_eq!(&*lazy, &92);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn force(this: &LazyCell<T, F>) -> &T {
|
||||||
|
this.cell.get_or_init(|| match this.init.take() {
|
||||||
|
Some(f) => f(),
|
||||||
|
None => panic!("`Lazy` instance has previously been poisoned"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
LazyCell::force(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: Default> Default for LazyCell<T> {
|
||||||
|
/// Creates a new lazy value using `Default` as the initializing function.
|
||||||
|
fn default() -> LazyCell<T> {
|
||||||
|
LazyCell::new(T::default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
|
||||||
|
}
|
||||||
|
}
|
283
library/core/src/cell/once.rs
Normal file
283
library/core/src/cell/once.rs
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
use crate::cell::UnsafeCell;
|
||||||
|
use crate::fmt;
|
||||||
|
use crate::mem;
|
||||||
|
|
||||||
|
/// A cell which can be written to only once.
|
||||||
|
///
|
||||||
|
/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value.
|
||||||
|
/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::OnceCell;
|
||||||
|
///
|
||||||
|
/// let cell = OnceCell::new();
|
||||||
|
/// assert!(cell.get().is_none());
|
||||||
|
///
|
||||||
|
/// let value: &String = cell.get_or_init(|| {
|
||||||
|
/// "Hello, World!".to_string()
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(value, "Hello, World!");
|
||||||
|
/// assert!(cell.get().is_some());
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub struct OnceCell<T> {
|
||||||
|
// Invariant: written to at most once.
|
||||||
|
inner: UnsafeCell<Option<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> OnceCell<T> {
|
||||||
|
/// Creates a new empty cell.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new() -> OnceCell<T> {
|
||||||
|
OnceCell { inner: UnsafeCell::new(None) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the reference to the underlying value.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the cell is empty.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn get(&self) -> Option<&T> {
|
||||||
|
// SAFETY: Safe due to `inner`'s invariant
|
||||||
|
unsafe { &*self.inner.get() }.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the mutable reference to the underlying value.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the cell is empty.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn get_mut(&mut self) -> Option<&mut T> {
|
||||||
|
self.inner.get_mut().as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the contents of the cell to `value`.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This method returns `Ok(())` if the cell was empty and `Err(value)` if
|
||||||
|
/// it was full.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::OnceCell;
|
||||||
|
///
|
||||||
|
/// let cell = OnceCell::new();
|
||||||
|
/// assert!(cell.get().is_none());
|
||||||
|
///
|
||||||
|
/// assert_eq!(cell.set(92), Ok(()));
|
||||||
|
/// assert_eq!(cell.set(62), Err(62));
|
||||||
|
///
|
||||||
|
/// assert!(cell.get().is_some());
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn set(&self, value: T) -> Result<(), T> {
|
||||||
|
// SAFETY: Safe because we cannot have overlapping mutable borrows
|
||||||
|
let slot = unsafe { &*self.inner.get() };
|
||||||
|
if slot.is_some() {
|
||||||
|
return Err(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: This is the only place where we set the slot, no races
|
||||||
|
// due to reentrancy/concurrency are possible, and we've
|
||||||
|
// checked that slot is currently `None`, so this write
|
||||||
|
// maintains the `inner`'s invariant.
|
||||||
|
let slot = unsafe { &mut *self.inner.get() };
|
||||||
|
*slot = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the contents of the cell, initializing it with `f`
|
||||||
|
/// if the cell was empty.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If `f` panics, the panic is propagated to the caller, and the cell
|
||||||
|
/// remains uninitialized.
|
||||||
|
///
|
||||||
|
/// It is an error to reentrantly initialize the cell from `f`. Doing
|
||||||
|
/// so results in a panic.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::OnceCell;
|
||||||
|
///
|
||||||
|
/// let cell = OnceCell::new();
|
||||||
|
/// let value = cell.get_or_init(|| 92);
|
||||||
|
/// assert_eq!(value, &92);
|
||||||
|
/// let value = cell.get_or_init(|| unreachable!());
|
||||||
|
/// assert_eq!(value, &92);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn get_or_init<F>(&self, f: F) -> &T
|
||||||
|
where
|
||||||
|
F: FnOnce() -> T,
|
||||||
|
{
|
||||||
|
match self.get_or_try_init(|| Ok::<T, !>(f())) {
|
||||||
|
Ok(val) => val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the contents of the cell, initializing it with `f` if
|
||||||
|
/// the cell was empty. If the cell was empty and `f` failed, an
|
||||||
|
/// error is returned.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If `f` panics, the panic is propagated to the caller, and the cell
|
||||||
|
/// remains uninitialized.
|
||||||
|
///
|
||||||
|
/// It is an error to reentrantly initialize the cell from `f`. Doing
|
||||||
|
/// so results in a panic.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::OnceCell;
|
||||||
|
///
|
||||||
|
/// let cell = OnceCell::new();
|
||||||
|
/// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
|
||||||
|
/// assert!(cell.get().is_none());
|
||||||
|
/// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
|
||||||
|
/// Ok(92)
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(value, Ok(&92));
|
||||||
|
/// assert_eq!(cell.get(), Some(&92))
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<T, E>,
|
||||||
|
{
|
||||||
|
if let Some(val) = self.get() {
|
||||||
|
return Ok(val);
|
||||||
|
}
|
||||||
|
/// Avoid inlining the initialization closure into the common path that fetches
|
||||||
|
/// the already initialized value
|
||||||
|
#[cold]
|
||||||
|
fn outlined_call<F, T, E>(f: F) -> Result<T, E>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<T, E>,
|
||||||
|
{
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
let val = outlined_call(f)?;
|
||||||
|
// Note that *some* forms of reentrant initialization might lead to
|
||||||
|
// UB (see `reentrant_init` test). I believe that just removing this
|
||||||
|
// `assert`, while keeping `set/get` would be sound, but it seems
|
||||||
|
// better to panic, rather than to silently use an old value.
|
||||||
|
assert!(self.set(val).is_ok(), "reentrant init");
|
||||||
|
Ok(self.get().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes the cell, returning the wrapped value.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the cell was empty.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::OnceCell;
|
||||||
|
///
|
||||||
|
/// let cell: OnceCell<String> = OnceCell::new();
|
||||||
|
/// assert_eq!(cell.into_inner(), None);
|
||||||
|
///
|
||||||
|
/// let cell = OnceCell::new();
|
||||||
|
/// cell.set("hello".to_string()).unwrap();
|
||||||
|
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn into_inner(self) -> Option<T> {
|
||||||
|
// Because `into_inner` takes `self` by value, the compiler statically verifies
|
||||||
|
// that it is not currently borrowed. So it is safe to move out `Option<T>`.
|
||||||
|
self.inner.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
|
||||||
|
///
|
||||||
|
/// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
|
||||||
|
///
|
||||||
|
/// Safety is guaranteed by requiring a mutable reference.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::cell::OnceCell;
|
||||||
|
///
|
||||||
|
/// let mut cell: OnceCell<String> = OnceCell::new();
|
||||||
|
/// assert_eq!(cell.take(), None);
|
||||||
|
///
|
||||||
|
/// let mut cell = OnceCell::new();
|
||||||
|
/// cell.set("hello".to_string()).unwrap();
|
||||||
|
/// assert_eq!(cell.take(), Some("hello".to_string()));
|
||||||
|
/// assert_eq!(cell.get(), None);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn take(&mut self) -> Option<T> {
|
||||||
|
mem::take(self).into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T> Default for OnceCell<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.get() {
|
||||||
|
Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
|
||||||
|
None => f.write_str("OnceCell(Uninit)"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: Clone> Clone for OnceCell<T> {
|
||||||
|
fn clone(&self) -> OnceCell<T> {
|
||||||
|
let res = OnceCell::new();
|
||||||
|
if let Some(value) = self.get() {
|
||||||
|
match res.set(value.clone()) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: PartialEq> PartialEq for OnceCell<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.get() == other.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: Eq> Eq for OnceCell<T> {}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T> const From<T> for OnceCell<T> {
|
||||||
|
/// Creates a new `OnceCell<T>` which already contains the given `value`.
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
OnceCell { inner: UnsafeCell::new(Some(value)) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,389 +1 @@
|
||||||
//! Lazy values and one-time initialization of static data.
|
//! Lazy values and one-time initialization of static data.
|
||||||
|
|
||||||
use crate::cell::{Cell, UnsafeCell};
|
|
||||||
use crate::fmt;
|
|
||||||
use crate::mem;
|
|
||||||
use crate::ops::Deref;
|
|
||||||
|
|
||||||
/// A cell which can be written to only once.
|
|
||||||
///
|
|
||||||
/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value.
|
|
||||||
/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::OnceCell;
|
|
||||||
///
|
|
||||||
/// let cell = OnceCell::new();
|
|
||||||
/// assert!(cell.get().is_none());
|
|
||||||
///
|
|
||||||
/// let value: &String = cell.get_or_init(|| {
|
|
||||||
/// "Hello, World!".to_string()
|
|
||||||
/// });
|
|
||||||
/// assert_eq!(value, "Hello, World!");
|
|
||||||
/// assert!(cell.get().is_some());
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub struct OnceCell<T> {
|
|
||||||
// Invariant: written to at most once.
|
|
||||||
inner: UnsafeCell<Option<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T> Default for OnceCell<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.get() {
|
|
||||||
Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
|
|
||||||
None => f.write_str("OnceCell(Uninit)"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: Clone> Clone for OnceCell<T> {
|
|
||||||
fn clone(&self) -> OnceCell<T> {
|
|
||||||
let res = OnceCell::new();
|
|
||||||
if let Some(value) = self.get() {
|
|
||||||
match res.set(value.clone()) {
|
|
||||||
Ok(()) => (),
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: PartialEq> PartialEq for OnceCell<T> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.get() == other.get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: Eq> Eq for OnceCell<T> {}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T> const From<T> for OnceCell<T> {
|
|
||||||
/// Creates a new `OnceCell<T>` which already contains the given `value`.
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
OnceCell { inner: UnsafeCell::new(Some(value)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> OnceCell<T> {
|
|
||||||
/// Creates a new empty cell.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn new() -> OnceCell<T> {
|
|
||||||
OnceCell { inner: UnsafeCell::new(None) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the reference to the underlying value.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the cell is empty.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn get(&self) -> Option<&T> {
|
|
||||||
// SAFETY: Safe due to `inner`'s invariant
|
|
||||||
unsafe { &*self.inner.get() }.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the mutable reference to the underlying value.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the cell is empty.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn get_mut(&mut self) -> Option<&mut T> {
|
|
||||||
self.inner.get_mut().as_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the contents of the cell to `value`.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// This method returns `Ok(())` if the cell was empty and `Err(value)` if
|
|
||||||
/// it was full.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::OnceCell;
|
|
||||||
///
|
|
||||||
/// let cell = OnceCell::new();
|
|
||||||
/// assert!(cell.get().is_none());
|
|
||||||
///
|
|
||||||
/// assert_eq!(cell.set(92), Ok(()));
|
|
||||||
/// assert_eq!(cell.set(62), Err(62));
|
|
||||||
///
|
|
||||||
/// assert!(cell.get().is_some());
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn set(&self, value: T) -> Result<(), T> {
|
|
||||||
// SAFETY: Safe because we cannot have overlapping mutable borrows
|
|
||||||
let slot = unsafe { &*self.inner.get() };
|
|
||||||
if slot.is_some() {
|
|
||||||
return Err(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: This is the only place where we set the slot, no races
|
|
||||||
// due to reentrancy/concurrency are possible, and we've
|
|
||||||
// checked that slot is currently `None`, so this write
|
|
||||||
// maintains the `inner`'s invariant.
|
|
||||||
let slot = unsafe { &mut *self.inner.get() };
|
|
||||||
*slot = Some(value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the contents of the cell, initializing it with `f`
|
|
||||||
/// if the cell was empty.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If `f` panics, the panic is propagated to the caller, and the cell
|
|
||||||
/// remains uninitialized.
|
|
||||||
///
|
|
||||||
/// It is an error to reentrantly initialize the cell from `f`. Doing
|
|
||||||
/// so results in a panic.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::OnceCell;
|
|
||||||
///
|
|
||||||
/// let cell = OnceCell::new();
|
|
||||||
/// let value = cell.get_or_init(|| 92);
|
|
||||||
/// assert_eq!(value, &92);
|
|
||||||
/// let value = cell.get_or_init(|| unreachable!());
|
|
||||||
/// assert_eq!(value, &92);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn get_or_init<F>(&self, f: F) -> &T
|
|
||||||
where
|
|
||||||
F: FnOnce() -> T,
|
|
||||||
{
|
|
||||||
match self.get_or_try_init(|| Ok::<T, !>(f())) {
|
|
||||||
Ok(val) => val,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the contents of the cell, initializing it with `f` if
|
|
||||||
/// the cell was empty. If the cell was empty and `f` failed, an
|
|
||||||
/// error is returned.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If `f` panics, the panic is propagated to the caller, and the cell
|
|
||||||
/// remains uninitialized.
|
|
||||||
///
|
|
||||||
/// It is an error to reentrantly initialize the cell from `f`. Doing
|
|
||||||
/// so results in a panic.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::OnceCell;
|
|
||||||
///
|
|
||||||
/// let cell = OnceCell::new();
|
|
||||||
/// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
|
|
||||||
/// assert!(cell.get().is_none());
|
|
||||||
/// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
|
|
||||||
/// Ok(92)
|
|
||||||
/// });
|
|
||||||
/// assert_eq!(value, Ok(&92));
|
|
||||||
/// assert_eq!(cell.get(), Some(&92))
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
|
|
||||||
where
|
|
||||||
F: FnOnce() -> Result<T, E>,
|
|
||||||
{
|
|
||||||
if let Some(val) = self.get() {
|
|
||||||
return Ok(val);
|
|
||||||
}
|
|
||||||
/// Avoid inlining the initialization closure into the common path that fetches
|
|
||||||
/// the already initialized value
|
|
||||||
#[cold]
|
|
||||||
fn outlined_call<F, T, E>(f: F) -> Result<T, E>
|
|
||||||
where
|
|
||||||
F: FnOnce() -> Result<T, E>,
|
|
||||||
{
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
let val = outlined_call(f)?;
|
|
||||||
// Note that *some* forms of reentrant initialization might lead to
|
|
||||||
// UB (see `reentrant_init` test). I believe that just removing this
|
|
||||||
// `assert`, while keeping `set/get` would be sound, but it seems
|
|
||||||
// better to panic, rather than to silently use an old value.
|
|
||||||
assert!(self.set(val).is_ok(), "reentrant init");
|
|
||||||
Ok(self.get().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes the cell, returning the wrapped value.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the cell was empty.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::OnceCell;
|
|
||||||
///
|
|
||||||
/// let cell: OnceCell<String> = OnceCell::new();
|
|
||||||
/// assert_eq!(cell.into_inner(), None);
|
|
||||||
///
|
|
||||||
/// let cell = OnceCell::new();
|
|
||||||
/// cell.set("hello".to_string()).unwrap();
|
|
||||||
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn into_inner(self) -> Option<T> {
|
|
||||||
// Because `into_inner` takes `self` by value, the compiler statically verifies
|
|
||||||
// that it is not currently borrowed. So it is safe to move out `Option<T>`.
|
|
||||||
self.inner.into_inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
|
|
||||||
///
|
|
||||||
/// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
|
|
||||||
///
|
|
||||||
/// Safety is guaranteed by requiring a mutable reference.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::OnceCell;
|
|
||||||
///
|
|
||||||
/// let mut cell: OnceCell<String> = OnceCell::new();
|
|
||||||
/// assert_eq!(cell.take(), None);
|
|
||||||
///
|
|
||||||
/// let mut cell = OnceCell::new();
|
|
||||||
/// cell.set("hello".to_string()).unwrap();
|
|
||||||
/// assert_eq!(cell.take(), Some("hello".to_string()));
|
|
||||||
/// assert_eq!(cell.get(), None);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn take(&mut self) -> Option<T> {
|
|
||||||
mem::take(self).into_inner()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A value which is initialized on the first access.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::Lazy;
|
|
||||||
///
|
|
||||||
/// let lazy: Lazy<i32> = Lazy::new(|| {
|
|
||||||
/// println!("initializing");
|
|
||||||
/// 92
|
|
||||||
/// });
|
|
||||||
/// println!("ready");
|
|
||||||
/// println!("{}", *lazy);
|
|
||||||
/// println!("{}", *lazy);
|
|
||||||
///
|
|
||||||
/// // Prints:
|
|
||||||
/// // ready
|
|
||||||
/// // initializing
|
|
||||||
/// // 92
|
|
||||||
/// // 92
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub struct Lazy<T, F = fn() -> T> {
|
|
||||||
cell: OnceCell<T>,
|
|
||||||
init: Cell<Option<F>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, F> Lazy<T, F> {
|
|
||||||
/// Creates a new lazy value with the given initializing function.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// # fn main() {
|
|
||||||
/// use std::lazy::Lazy;
|
|
||||||
///
|
|
||||||
/// let hello = "Hello, World!".to_string();
|
|
||||||
///
|
|
||||||
/// let lazy = Lazy::new(|| hello.to_uppercase());
|
|
||||||
///
|
|
||||||
/// assert_eq!(&*lazy, "HELLO, WORLD!");
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub const fn new(init: F) -> Lazy<T, F> {
|
|
||||||
Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, F: FnOnce() -> T> Lazy<T, F> {
|
|
||||||
/// Forces the evaluation of this lazy value and returns a reference to
|
|
||||||
/// the result.
|
|
||||||
///
|
|
||||||
/// This is equivalent to the `Deref` impl, but is explicit.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::Lazy;
|
|
||||||
///
|
|
||||||
/// let lazy = Lazy::new(|| 92);
|
|
||||||
///
|
|
||||||
/// assert_eq!(Lazy::force(&lazy), &92);
|
|
||||||
/// assert_eq!(&*lazy, &92);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn force(this: &Lazy<T, F>) -> &T {
|
|
||||||
this.cell.get_or_init(|| match this.init.take() {
|
|
||||||
Some(f) => f(),
|
|
||||||
None => panic!("`Lazy` instance has previously been poisoned"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
|
|
||||||
type Target = T;
|
|
||||||
fn deref(&self) -> &T {
|
|
||||||
Lazy::force(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: Default> Default for Lazy<T> {
|
|
||||||
/// Creates a new lazy value using `Default` as the initializing function.
|
|
||||||
fn default() -> Lazy<T> {
|
|
||||||
Lazy::new(T::default)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use core::{
|
use core::{
|
||||||
cell::Cell,
|
cell::{Cell, LazyCell, OnceCell},
|
||||||
lazy::{Lazy, OnceCell},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering::SeqCst},
|
sync::atomic::{AtomicUsize, Ordering::SeqCst},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,7 +90,7 @@ fn into_inner() {
|
||||||
#[test]
|
#[test]
|
||||||
fn lazy_new() {
|
fn lazy_new() {
|
||||||
let called = Cell::new(0);
|
let called = Cell::new(0);
|
||||||
let x = Lazy::new(|| {
|
let x = LazyCell::new(|| {
|
||||||
called.set(called.get() + 1);
|
called.set(called.get() + 1);
|
||||||
92
|
92
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,10 +8,9 @@ use crate::io::prelude::*;
|
||||||
use crate::cell::{Cell, RefCell};
|
use crate::cell::{Cell, RefCell};
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
|
use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
|
||||||
use crate::lazy::SyncOnceCell;
|
|
||||||
use crate::pin::Pin;
|
use crate::pin::Pin;
|
||||||
use crate::sync::atomic::{AtomicBool, Ordering};
|
use crate::sync::atomic::{AtomicBool, Ordering};
|
||||||
use crate::sync::{Arc, Mutex, MutexGuard};
|
use crate::sync::{Arc, Mutex, MutexGuard, OnceLock};
|
||||||
use crate::sys::stdio;
|
use crate::sys::stdio;
|
||||||
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
||||||
|
|
||||||
|
@ -318,7 +317,7 @@ pub struct StdinLock<'a> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn stdin() -> Stdin {
|
pub fn stdin() -> Stdin {
|
||||||
static INSTANCE: SyncOnceCell<Mutex<BufReader<StdinRaw>>> = SyncOnceCell::new();
|
static INSTANCE: OnceLock<Mutex<BufReader<StdinRaw>>> = OnceLock::new();
|
||||||
Stdin {
|
Stdin {
|
||||||
inner: INSTANCE.get_or_init(|| {
|
inner: INSTANCE.get_or_init(|| {
|
||||||
Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw()))
|
Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw()))
|
||||||
|
@ -552,7 +551,7 @@ pub struct StdoutLock<'a> {
|
||||||
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
|
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static STDOUT: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = SyncOnceCell::new();
|
static STDOUT: OnceLock<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = OnceLock::new();
|
||||||
|
|
||||||
/// Constructs a new handle to the standard output of the current process.
|
/// Constructs a new handle to the standard output of the current process.
|
||||||
///
|
///
|
||||||
|
@ -837,7 +836,7 @@ pub fn stderr() -> Stderr {
|
||||||
// Note that unlike `stdout()` we don't use `at_exit` here to register a
|
// Note that unlike `stdout()` we don't use `at_exit` here to register a
|
||||||
// destructor. Stderr is not buffered , so there's no need to run a
|
// destructor. Stderr is not buffered , so there's no need to run a
|
||||||
// destructor for flushing the buffer
|
// destructor for flushing the buffer
|
||||||
static INSTANCE: SyncOnceCell<ReentrantMutex<RefCell<StderrRaw>>> = SyncOnceCell::new();
|
static INSTANCE: OnceLock<ReentrantMutex<RefCell<StderrRaw>>> = OnceLock::new();
|
||||||
|
|
||||||
Stderr {
|
Stderr {
|
||||||
inner: Pin::static_ref(&INSTANCE).get_or_init_pin(
|
inner: Pin::static_ref(&INSTANCE).get_or_init_pin(
|
||||||
|
|
|
@ -1,617 +1 @@
|
||||||
//! Lazy values and one-time initialization of static data.
|
//! Lazy values and one-time initialization of static data.
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
cell::{Cell, UnsafeCell},
|
|
||||||
fmt,
|
|
||||||
marker::PhantomData,
|
|
||||||
mem::MaybeUninit,
|
|
||||||
ops::{Deref, Drop},
|
|
||||||
panic::{RefUnwindSafe, UnwindSafe},
|
|
||||||
pin::Pin,
|
|
||||||
sync::Once,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub use core::lazy::*;
|
|
||||||
|
|
||||||
/// A synchronization primitive which can be written to only once.
|
|
||||||
///
|
|
||||||
/// This type is a thread-safe `OnceCell`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// static CELL: SyncOnceCell<String> = SyncOnceCell::new();
|
|
||||||
/// assert!(CELL.get().is_none());
|
|
||||||
///
|
|
||||||
/// std::thread::spawn(|| {
|
|
||||||
/// let value: &String = CELL.get_or_init(|| {
|
|
||||||
/// "Hello, World!".to_string()
|
|
||||||
/// });
|
|
||||||
/// assert_eq!(value, "Hello, World!");
|
|
||||||
/// }).join().unwrap();
|
|
||||||
///
|
|
||||||
/// let value: Option<&String> = CELL.get();
|
|
||||||
/// assert!(value.is_some());
|
|
||||||
/// assert_eq!(value.unwrap().as_str(), "Hello, World!");
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub struct SyncOnceCell<T> {
|
|
||||||
once: Once,
|
|
||||||
// Whether or not the value is initialized is tracked by `state_and_queue`.
|
|
||||||
value: UnsafeCell<MaybeUninit<T>>,
|
|
||||||
/// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
|
|
||||||
///
|
|
||||||
/// ```compile_fail,E0597
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// struct A<'a>(&'a str);
|
|
||||||
///
|
|
||||||
/// impl<'a> Drop for A<'a> {
|
|
||||||
/// fn drop(&mut self) {}
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let cell = SyncOnceCell::new();
|
|
||||||
/// {
|
|
||||||
/// let s = String::new();
|
|
||||||
/// let _ = cell.set(A(&s));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
_marker: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Why do we need `T: Send`?
|
|
||||||
// Thread A creates a `SyncOnceCell` and shares it with
|
|
||||||
// scoped thread B, which fills the cell, which is
|
|
||||||
// then destroyed by A. That is, destructor observes
|
|
||||||
// a sent value.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {}
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
unsafe impl<T: Send> Send for SyncOnceCell<T> {}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {}
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
|
|
||||||
impl<T> const Default for SyncOnceCell<T> {
|
|
||||||
/// Creates a new empty cell.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// assert_eq!(SyncOnceCell::<()>::new(), SyncOnceCell::default());
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
fn default() -> SyncOnceCell<T> {
|
|
||||||
SyncOnceCell::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.get() {
|
|
||||||
Some(v) => f.debug_tuple("Once").field(v).finish(),
|
|
||||||
None => f.write_str("Once(Uninit)"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: Clone> Clone for SyncOnceCell<T> {
|
|
||||||
fn clone(&self) -> SyncOnceCell<T> {
|
|
||||||
let cell = Self::new();
|
|
||||||
if let Some(value) = self.get() {
|
|
||||||
match cell.set(value.clone()) {
|
|
||||||
Ok(()) => (),
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cell
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T> From<T> for SyncOnceCell<T> {
|
|
||||||
/// Create a new cell with its contents set to `value`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// # fn main() -> Result<(), i32> {
|
|
||||||
/// let a = SyncOnceCell::from(3);
|
|
||||||
/// let b = SyncOnceCell::new();
|
|
||||||
/// b.set(3)?;
|
|
||||||
/// assert_eq!(a, b);
|
|
||||||
/// Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
let cell = Self::new();
|
|
||||||
match cell.set(value) {
|
|
||||||
Ok(()) => cell,
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: PartialEq> PartialEq for SyncOnceCell<T> {
|
|
||||||
fn eq(&self, other: &SyncOnceCell<T>) -> bool {
|
|
||||||
self.get() == other.get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: Eq> Eq for SyncOnceCell<T> {}
|
|
||||||
|
|
||||||
impl<T> SyncOnceCell<T> {
|
|
||||||
/// Creates a new empty cell.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn new() -> SyncOnceCell<T> {
|
|
||||||
SyncOnceCell {
|
|
||||||
once: Once::new(),
|
|
||||||
value: UnsafeCell::new(MaybeUninit::uninit()),
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the reference to the underlying value.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the cell is empty, or being initialized. This
|
|
||||||
/// method never blocks.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn get(&self) -> Option<&T> {
|
|
||||||
if self.is_initialized() {
|
|
||||||
// Safe b/c checked is_initialized
|
|
||||||
Some(unsafe { self.get_unchecked() })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the mutable reference to the underlying value.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the cell is empty. This method never blocks.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn get_mut(&mut self) -> Option<&mut T> {
|
|
||||||
if self.is_initialized() {
|
|
||||||
// Safe b/c checked is_initialized and we have a unique access
|
|
||||||
Some(unsafe { self.get_unchecked_mut() })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the contents of this cell to `value`.
|
|
||||||
///
|
|
||||||
/// May block if another thread is currently attempting to initialize the cell. The cell is
|
|
||||||
/// guaranteed to contain a value when set returns, though not necessarily the one provided.
|
|
||||||
///
|
|
||||||
/// Returns `Ok(())` if the cell's value was set by this call.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// static CELL: SyncOnceCell<i32> = SyncOnceCell::new();
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// assert!(CELL.get().is_none());
|
|
||||||
///
|
|
||||||
/// std::thread::spawn(|| {
|
|
||||||
/// assert_eq!(CELL.set(92), Ok(()));
|
|
||||||
/// }).join().unwrap();
|
|
||||||
///
|
|
||||||
/// assert_eq!(CELL.set(62), Err(62));
|
|
||||||
/// assert_eq!(CELL.get(), Some(&92));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn set(&self, value: T) -> Result<(), T> {
|
|
||||||
let mut value = Some(value);
|
|
||||||
self.get_or_init(|| value.take().unwrap());
|
|
||||||
match value {
|
|
||||||
None => Ok(()),
|
|
||||||
Some(value) => Err(value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the contents of the cell, initializing it with `f` if the cell
|
|
||||||
/// was empty.
|
|
||||||
///
|
|
||||||
/// Many threads may call `get_or_init` concurrently with different
|
|
||||||
/// initializing functions, but it is guaranteed that only one function
|
|
||||||
/// will be executed.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If `f` panics, the panic is propagated to the caller, and the cell
|
|
||||||
/// remains uninitialized.
|
|
||||||
///
|
|
||||||
/// It is an error to reentrantly initialize the cell from `f`. The
|
|
||||||
/// exact outcome is unspecified. Current implementation deadlocks, but
|
|
||||||
/// this may be changed to a panic in the future.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// let cell = SyncOnceCell::new();
|
|
||||||
/// let value = cell.get_or_init(|| 92);
|
|
||||||
/// assert_eq!(value, &92);
|
|
||||||
/// let value = cell.get_or_init(|| unreachable!());
|
|
||||||
/// assert_eq!(value, &92);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn get_or_init<F>(&self, f: F) -> &T
|
|
||||||
where
|
|
||||||
F: FnOnce() -> T,
|
|
||||||
{
|
|
||||||
match self.get_or_try_init(|| Ok::<T, !>(f())) {
|
|
||||||
Ok(val) => val,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the contents of the cell, initializing it with `f` if
|
|
||||||
/// the cell was empty. If the cell was empty and `f` failed, an
|
|
||||||
/// error is returned.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If `f` panics, the panic is propagated to the caller, and
|
|
||||||
/// the cell remains uninitialized.
|
|
||||||
///
|
|
||||||
/// It is an error to reentrantly initialize the cell from `f`.
|
|
||||||
/// The exact outcome is unspecified. Current implementation
|
|
||||||
/// deadlocks, but this may be changed to a panic in the future.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// let cell = SyncOnceCell::new();
|
|
||||||
/// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
|
|
||||||
/// assert!(cell.get().is_none());
|
|
||||||
/// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
|
|
||||||
/// Ok(92)
|
|
||||||
/// });
|
|
||||||
/// assert_eq!(value, Ok(&92));
|
|
||||||
/// assert_eq!(cell.get(), Some(&92))
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
|
|
||||||
where
|
|
||||||
F: FnOnce() -> Result<T, E>,
|
|
||||||
{
|
|
||||||
// Fast path check
|
|
||||||
// NOTE: We need to perform an acquire on the state in this method
|
|
||||||
// in order to correctly synchronize `SyncLazy::force`. This is
|
|
||||||
// currently done by calling `self.get()`, which in turn calls
|
|
||||||
// `self.is_initialized()`, which in turn performs the acquire.
|
|
||||||
if let Some(value) = self.get() {
|
|
||||||
return Ok(value);
|
|
||||||
}
|
|
||||||
self.initialize(f)?;
|
|
||||||
|
|
||||||
debug_assert!(self.is_initialized());
|
|
||||||
|
|
||||||
// SAFETY: The inner value has been initialized
|
|
||||||
Ok(unsafe { self.get_unchecked() })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Internal-only API that gets the contents of the cell, initializing it
|
|
||||||
/// in two steps with `f` and `g` if the cell was empty.
|
|
||||||
///
|
|
||||||
/// `f` is called to construct the value, which is then moved into the cell
|
|
||||||
/// and given as a (pinned) mutable reference to `g` to finish
|
|
||||||
/// initialization.
|
|
||||||
///
|
|
||||||
/// This allows `g` to inspect an manipulate the value after it has been
|
|
||||||
/// moved into its final place in the cell, but before the cell is
|
|
||||||
/// considered initialized.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If `f` or `g` panics, the panic is propagated to the caller, and the
|
|
||||||
/// cell remains uninitialized.
|
|
||||||
///
|
|
||||||
/// With the current implementation, if `g` panics, the value from `f` will
|
|
||||||
/// not be dropped. This should probably be fixed if this is ever used for
|
|
||||||
/// a type where this matters.
|
|
||||||
///
|
|
||||||
/// It is an error to reentrantly initialize the cell from `f`. The exact
|
|
||||||
/// outcome is unspecified. Current implementation deadlocks, but this may
|
|
||||||
/// be changed to a panic in the future.
|
|
||||||
pub(crate) fn get_or_init_pin<F, G>(self: Pin<&Self>, f: F, g: G) -> Pin<&T>
|
|
||||||
where
|
|
||||||
F: FnOnce() -> T,
|
|
||||||
G: FnOnce(Pin<&mut T>),
|
|
||||||
{
|
|
||||||
if let Some(value) = self.get_ref().get() {
|
|
||||||
// SAFETY: The inner value was already initialized, and will not be
|
|
||||||
// moved anymore.
|
|
||||||
return unsafe { Pin::new_unchecked(value) };
|
|
||||||
}
|
|
||||||
|
|
||||||
let slot = &self.value;
|
|
||||||
|
|
||||||
// Ignore poisoning from other threads
|
|
||||||
// If another thread panics, then we'll be able to run our closure
|
|
||||||
self.once.call_once_force(|_| {
|
|
||||||
let value = f();
|
|
||||||
// SAFETY: We use the Once (self.once) to guarantee unique access
|
|
||||||
// to the UnsafeCell (slot).
|
|
||||||
let value: &mut T = unsafe { (&mut *slot.get()).write(value) };
|
|
||||||
// SAFETY: The value has been written to its final place in
|
|
||||||
// self.value. We do not to move it anymore, which we promise here
|
|
||||||
// with a Pin<&mut T>.
|
|
||||||
g(unsafe { Pin::new_unchecked(value) });
|
|
||||||
});
|
|
||||||
|
|
||||||
// SAFETY: The inner value has been initialized, and will not be moved
|
|
||||||
// anymore.
|
|
||||||
unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes the `SyncOnceCell`, returning the wrapped value. Returns
|
|
||||||
/// `None` if the cell was empty.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// let cell: SyncOnceCell<String> = SyncOnceCell::new();
|
|
||||||
/// assert_eq!(cell.into_inner(), None);
|
|
||||||
///
|
|
||||||
/// let cell = SyncOnceCell::new();
|
|
||||||
/// cell.set("hello".to_string()).unwrap();
|
|
||||||
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn into_inner(mut self) -> Option<T> {
|
|
||||||
self.take()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
|
|
||||||
///
|
|
||||||
/// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized.
|
|
||||||
///
|
|
||||||
/// Safety is guaranteed by requiring a mutable reference.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncOnceCell;
|
|
||||||
///
|
|
||||||
/// let mut cell: SyncOnceCell<String> = SyncOnceCell::new();
|
|
||||||
/// assert_eq!(cell.take(), None);
|
|
||||||
///
|
|
||||||
/// let mut cell = SyncOnceCell::new();
|
|
||||||
/// cell.set("hello".to_string()).unwrap();
|
|
||||||
/// assert_eq!(cell.take(), Some("hello".to_string()));
|
|
||||||
/// assert_eq!(cell.get(), None);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn take(&mut self) -> Option<T> {
|
|
||||||
if self.is_initialized() {
|
|
||||||
self.once = Once::new();
|
|
||||||
// SAFETY: `self.value` is initialized and contains a valid `T`.
|
|
||||||
// `self.once` is reset, so `is_initialized()` will be false again
|
|
||||||
// which prevents the value from being read twice.
|
|
||||||
unsafe { Some((&mut *self.value.get()).assume_init_read()) }
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_initialized(&self) -> bool {
|
|
||||||
self.once.is_completed()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cold]
|
|
||||||
fn initialize<F, E>(&self, f: F) -> Result<(), E>
|
|
||||||
where
|
|
||||||
F: FnOnce() -> Result<T, E>,
|
|
||||||
{
|
|
||||||
let mut res: Result<(), E> = Ok(());
|
|
||||||
let slot = &self.value;
|
|
||||||
|
|
||||||
// Ignore poisoning from other threads
|
|
||||||
// If another thread panics, then we'll be able to run our closure
|
|
||||||
self.once.call_once_force(|p| {
|
|
||||||
match f() {
|
|
||||||
Ok(value) => {
|
|
||||||
unsafe { (&mut *slot.get()).write(value) };
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
res = Err(e);
|
|
||||||
|
|
||||||
// Treat the underlying `Once` as poisoned since we
|
|
||||||
// failed to initialize our value. Calls
|
|
||||||
p.poison();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The value must be initialized
|
|
||||||
unsafe fn get_unchecked(&self) -> &T {
|
|
||||||
debug_assert!(self.is_initialized());
|
|
||||||
(&*self.value.get()).assume_init_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The value must be initialized
|
|
||||||
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
|
|
||||||
debug_assert!(self.is_initialized());
|
|
||||||
(&mut *self.value.get()).assume_init_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if self.is_initialized() {
|
|
||||||
// SAFETY: The cell is initialized and being dropped, so it can't
|
|
||||||
// be accessed again. We also don't touch the `T` other than
|
|
||||||
// dropping it, which validates our usage of #[may_dangle].
|
|
||||||
unsafe { (&mut *self.value.get()).assume_init_drop() };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A value which is initialized on the first access.
|
|
||||||
///
|
|
||||||
/// This type is a thread-safe `Lazy`, and can be used in statics.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::collections::HashMap;
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncLazy;
|
|
||||||
///
|
|
||||||
/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| {
|
|
||||||
/// println!("initializing");
|
|
||||||
/// let mut m = HashMap::new();
|
|
||||||
/// m.insert(13, "Spica".to_string());
|
|
||||||
/// m.insert(74, "Hoyten".to_string());
|
|
||||||
/// m
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// println!("ready");
|
|
||||||
/// std::thread::spawn(|| {
|
|
||||||
/// println!("{:?}", HASHMAP.get(&13));
|
|
||||||
/// }).join().unwrap();
|
|
||||||
/// println!("{:?}", HASHMAP.get(&74));
|
|
||||||
///
|
|
||||||
/// // Prints:
|
|
||||||
/// // ready
|
|
||||||
/// // initializing
|
|
||||||
/// // Some("Spica")
|
|
||||||
/// // Some("Hoyten")
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub struct SyncLazy<T, F = fn() -> T> {
|
|
||||||
cell: SyncOnceCell<T>,
|
|
||||||
init: Cell<Option<F>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine
|
|
||||||
// to not impl `Sync` for `F`
|
|
||||||
// we do create a `&mut Option<F>` in `force`, but this is
|
|
||||||
// properly synchronized, so it only happens once
|
|
||||||
// so it also does not contribute to this impl.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {}
|
|
||||||
// auto-derived `Send` impl is OK.
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T, F: UnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {}
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T, F: UnwindSafe> UnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: UnwindSafe {}
|
|
||||||
|
|
||||||
impl<T, F> SyncLazy<T, F> {
|
|
||||||
/// Creates a new lazy value with the given initializing
|
|
||||||
/// function.
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub const fn new(f: F) -> SyncLazy<T, F> {
|
|
||||||
SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, F: FnOnce() -> T> SyncLazy<T, F> {
|
|
||||||
/// Forces the evaluation of this lazy value and
|
|
||||||
/// returns a reference to result. This is equivalent
|
|
||||||
/// to the `Deref` impl, but is explicit.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(once_cell)]
|
|
||||||
///
|
|
||||||
/// use std::lazy::SyncLazy;
|
|
||||||
///
|
|
||||||
/// let lazy = SyncLazy::new(|| 92);
|
|
||||||
///
|
|
||||||
/// assert_eq!(SyncLazy::force(&lazy), &92);
|
|
||||||
/// assert_eq!(&*lazy, &92);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
pub fn force(this: &SyncLazy<T, F>) -> &T {
|
|
||||||
this.cell.get_or_init(|| match this.init.take() {
|
|
||||||
Some(f) => f(),
|
|
||||||
None => panic!("Lazy instance has previously been poisoned"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> {
|
|
||||||
type Target = T;
|
|
||||||
fn deref(&self) -> &T {
|
|
||||||
SyncLazy::force(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
|
||||||
impl<T: Default> Default for SyncLazy<T> {
|
|
||||||
/// Creates a new lazy value using `Default` as the initializing function.
|
|
||||||
fn default() -> SyncLazy<T> {
|
|
||||||
SyncLazy::new(T::default)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
121
library/std/src/sync/lazy_lock.rs
Normal file
121
library/std/src/sync/lazy_lock.rs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
use crate::cell::Cell;
|
||||||
|
use crate::fmt;
|
||||||
|
use crate::ops::Deref;
|
||||||
|
use crate::panic::{RefUnwindSafe, UnwindSafe};
|
||||||
|
use crate::sync::OnceLock;
|
||||||
|
|
||||||
|
/// A value which is initialized on the first access.
|
||||||
|
///
|
||||||
|
/// This type is a thread-safe `Lazy`, and can be used in statics.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::collections::HashMap;
|
||||||
|
///
|
||||||
|
/// use std::sync::LazyLock;
|
||||||
|
///
|
||||||
|
/// static HASHMAP: LazyLock<HashMap<i32, String>> = LazyLock::new(|| {
|
||||||
|
/// println!("initializing");
|
||||||
|
/// let mut m = HashMap::new();
|
||||||
|
/// m.insert(13, "Spica".to_string());
|
||||||
|
/// m.insert(74, "Hoyten".to_string());
|
||||||
|
/// m
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// println!("ready");
|
||||||
|
/// std::thread::spawn(|| {
|
||||||
|
/// println!("{:?}", HASHMAP.get(&13));
|
||||||
|
/// }).join().unwrap();
|
||||||
|
/// println!("{:?}", HASHMAP.get(&74));
|
||||||
|
///
|
||||||
|
/// // Prints:
|
||||||
|
/// // ready
|
||||||
|
/// // initializing
|
||||||
|
/// // Some("Spica")
|
||||||
|
/// // Some("Hoyten")
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub struct LazyLock<T, F = fn() -> T> {
|
||||||
|
cell: OnceLock<T>,
|
||||||
|
init: Cell<Option<F>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F> LazyLock<T, F> {
|
||||||
|
/// Creates a new lazy value with the given initializing
|
||||||
|
/// function.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub const fn new(f: F) -> LazyLock<T, F> {
|
||||||
|
LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
|
||||||
|
/// Forces the evaluation of this lazy value and
|
||||||
|
/// returns a reference to result. This is equivalent
|
||||||
|
/// to the `Deref` impl, but is explicit.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::LazyLock;
|
||||||
|
///
|
||||||
|
/// let lazy = LazyLock::new(|| 92);
|
||||||
|
///
|
||||||
|
/// assert_eq!(LazyLock::force(&lazy), &92);
|
||||||
|
/// assert_eq!(&*lazy, &92);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn force(this: &LazyLock<T, F>) -> &T {
|
||||||
|
this.cell.get_or_init(|| match this.init.take() {
|
||||||
|
Some(f) => f(),
|
||||||
|
None => panic!("Lazy instance has previously been poisoned"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
LazyLock::force(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: Default> Default for LazyLock<T> {
|
||||||
|
/// Creates a new lazy value using `Default` as the initializing function.
|
||||||
|
fn default() -> LazyLock<T> {
|
||||||
|
LazyLock::new(T::default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
|
||||||
|
// to not impl `Sync` for `F`
|
||||||
|
// we do create a `&mut Option<F>` in `force`, but this is
|
||||||
|
// properly synchronized, so it only happens once
|
||||||
|
// so it also does not contribute to this impl.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
unsafe impl<T, F: Send> Sync for LazyLock<T, F> where OnceLock<T>: Sync {}
|
||||||
|
// auto-derived `Send` impl is OK.
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> where OnceLock<T>: RefUnwindSafe {}
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T, F: UnwindSafe> UnwindSafe for LazyLock<T, F> where OnceLock<T>: UnwindSafe {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
143
library/std/src/sync/lazy_lock/tests.rs
Normal file
143
library/std/src/sync/lazy_lock/tests.rs
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
use crate::{
|
||||||
|
cell::LazyCell,
|
||||||
|
panic,
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||||
|
Mutex,
|
||||||
|
},
|
||||||
|
sync::{LazyLock, OnceLock},
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
|
||||||
|
thread::spawn(f).join().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lazy_default() {
|
||||||
|
static CALLED: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
struct Foo(u8);
|
||||||
|
impl Default for Foo {
|
||||||
|
fn default() -> Self {
|
||||||
|
CALLED.fetch_add(1, SeqCst);
|
||||||
|
Foo(42)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lazy: LazyCell<Mutex<Foo>> = <_>::default();
|
||||||
|
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 0);
|
||||||
|
|
||||||
|
assert_eq!(lazy.lock().unwrap().0, 42);
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 1);
|
||||||
|
|
||||||
|
lazy.lock().unwrap().0 = 21;
|
||||||
|
|
||||||
|
assert_eq!(lazy.lock().unwrap().0, 21);
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lazy_poisoning() {
|
||||||
|
let x: LazyCell<String> = LazyCell::new(|| panic!("kaboom"));
|
||||||
|
for _ in 0..2 {
|
||||||
|
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
|
||||||
|
assert!(res.is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||||
|
fn sync_lazy_new() {
|
||||||
|
static CALLED: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
static SYNC_LAZY: LazyLock<i32> = LazyLock::new(|| {
|
||||||
|
CALLED.fetch_add(1, SeqCst);
|
||||||
|
92
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 0);
|
||||||
|
|
||||||
|
spawn_and_wait(|| {
|
||||||
|
let y = *SYNC_LAZY - 30;
|
||||||
|
assert_eq!(y, 62);
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
let y = *SYNC_LAZY - 30;
|
||||||
|
assert_eq!(y, 62);
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sync_lazy_default() {
|
||||||
|
static CALLED: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
struct Foo(u8);
|
||||||
|
impl Default for Foo {
|
||||||
|
fn default() -> Self {
|
||||||
|
CALLED.fetch_add(1, SeqCst);
|
||||||
|
Foo(42)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lazy: LazyLock<Mutex<Foo>> = <_>::default();
|
||||||
|
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 0);
|
||||||
|
|
||||||
|
assert_eq!(lazy.lock().unwrap().0, 42);
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 1);
|
||||||
|
|
||||||
|
lazy.lock().unwrap().0 = 21;
|
||||||
|
|
||||||
|
assert_eq!(lazy.lock().unwrap().0, 21);
|
||||||
|
assert_eq!(CALLED.load(SeqCst), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||||
|
fn static_sync_lazy() {
|
||||||
|
static XS: LazyLock<Vec<i32>> = LazyLock::new(|| {
|
||||||
|
let mut xs = Vec::new();
|
||||||
|
xs.push(1);
|
||||||
|
xs.push(2);
|
||||||
|
xs.push(3);
|
||||||
|
xs
|
||||||
|
});
|
||||||
|
|
||||||
|
spawn_and_wait(|| {
|
||||||
|
assert_eq!(&*XS, &vec![1, 2, 3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(&*XS, &vec![1, 2, 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn static_sync_lazy_via_fn() {
|
||||||
|
fn xs() -> &'static Vec<i32> {
|
||||||
|
static XS: OnceLock<Vec<i32>> = OnceLock::new();
|
||||||
|
XS.get_or_init(|| {
|
||||||
|
let mut xs = Vec::new();
|
||||||
|
xs.push(1);
|
||||||
|
xs.push(2);
|
||||||
|
xs.push(3);
|
||||||
|
xs
|
||||||
|
})
|
||||||
|
}
|
||||||
|
assert_eq!(xs(), &vec![1, 2, 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sync_lazy_poisoning() {
|
||||||
|
let x: LazyLock<String> = LazyLock::new(|| panic!("kaboom"));
|
||||||
|
for _ in 0..2 {
|
||||||
|
let res = panic::catch_unwind(|| x.len());
|
||||||
|
assert!(res.is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_sync_send() {
|
||||||
|
fn assert_traits<T: Send + Sync>() {}
|
||||||
|
assert_traits::<LazyLock<String>>();
|
||||||
|
}
|
|
@ -170,11 +170,18 @@ pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult};
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub use self::lazy_lock::LazyLock;
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub use self::once_lock::OnceLock;
|
||||||
|
|
||||||
pub mod mpsc;
|
pub mod mpsc;
|
||||||
|
|
||||||
mod barrier;
|
mod barrier;
|
||||||
mod condvar;
|
mod condvar;
|
||||||
|
mod lazy_lock;
|
||||||
mod mutex;
|
mod mutex;
|
||||||
mod once;
|
mod once;
|
||||||
|
mod once_lock;
|
||||||
mod poison;
|
mod poison;
|
||||||
mod rwlock;
|
mod rwlock;
|
||||||
|
|
496
library/std/src/sync/once_lock.rs
Normal file
496
library/std/src/sync/once_lock.rs
Normal file
|
@ -0,0 +1,496 @@
|
||||||
|
use crate::cell::UnsafeCell;
|
||||||
|
use crate::fmt;
|
||||||
|
use crate::marker::PhantomData;
|
||||||
|
use crate::mem::MaybeUninit;
|
||||||
|
use crate::panic::{RefUnwindSafe, UnwindSafe};
|
||||||
|
use crate::pin::Pin;
|
||||||
|
use crate::sync::Once;
|
||||||
|
|
||||||
|
/// A synchronization primitive which can be written to only once.
|
||||||
|
///
|
||||||
|
/// This type is a thread-safe `OnceCell`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// static CELL: OnceLock<String> = OnceLock::new();
|
||||||
|
/// assert!(CELL.get().is_none());
|
||||||
|
///
|
||||||
|
/// std::thread::spawn(|| {
|
||||||
|
/// let value: &String = CELL.get_or_init(|| {
|
||||||
|
/// "Hello, World!".to_string()
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(value, "Hello, World!");
|
||||||
|
/// }).join().unwrap();
|
||||||
|
///
|
||||||
|
/// let value: Option<&String> = CELL.get();
|
||||||
|
/// assert!(value.is_some());
|
||||||
|
/// assert_eq!(value.unwrap().as_str(), "Hello, World!");
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub struct OnceLock<T> {
|
||||||
|
once: Once,
|
||||||
|
// Whether or not the value is initialized is tracked by `state_and_queue`.
|
||||||
|
value: UnsafeCell<MaybeUninit<T>>,
|
||||||
|
/// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
|
||||||
|
///
|
||||||
|
/// ```compile_fail,E0597
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// struct A<'a>(&'a str);
|
||||||
|
///
|
||||||
|
/// impl<'a> Drop for A<'a> {
|
||||||
|
/// fn drop(&mut self) {}
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let cell = OnceLock::new();
|
||||||
|
/// {
|
||||||
|
/// let s = String::new();
|
||||||
|
/// let _ = cell.set(A(&s));
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> OnceLock<T> {
|
||||||
|
/// Creates a new empty cell.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new() -> OnceLock<T> {
|
||||||
|
OnceLock {
|
||||||
|
once: Once::new(),
|
||||||
|
value: UnsafeCell::new(MaybeUninit::uninit()),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the reference to the underlying value.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the cell is empty, or being initialized. This
|
||||||
|
/// method never blocks.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn get(&self) -> Option<&T> {
|
||||||
|
if self.is_initialized() {
|
||||||
|
// Safe b/c checked is_initialized
|
||||||
|
Some(unsafe { self.get_unchecked() })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the mutable reference to the underlying value.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the cell is empty. This method never blocks.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn get_mut(&mut self) -> Option<&mut T> {
|
||||||
|
if self.is_initialized() {
|
||||||
|
// Safe b/c checked is_initialized and we have a unique access
|
||||||
|
Some(unsafe { self.get_unchecked_mut() })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the contents of this cell to `value`.
|
||||||
|
///
|
||||||
|
/// May block if another thread is currently attempting to initialize the cell. The cell is
|
||||||
|
/// guaranteed to contain a value when set returns, though not necessarily the one provided.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(())` if the cell's value was set by this call.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// static CELL: OnceLock<i32> = OnceLock::new();
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// assert!(CELL.get().is_none());
|
||||||
|
///
|
||||||
|
/// std::thread::spawn(|| {
|
||||||
|
/// assert_eq!(CELL.set(92), Ok(()));
|
||||||
|
/// }).join().unwrap();
|
||||||
|
///
|
||||||
|
/// assert_eq!(CELL.set(62), Err(62));
|
||||||
|
/// assert_eq!(CELL.get(), Some(&92));
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn set(&self, value: T) -> Result<(), T> {
|
||||||
|
let mut value = Some(value);
|
||||||
|
self.get_or_init(|| value.take().unwrap());
|
||||||
|
match value {
|
||||||
|
None => Ok(()),
|
||||||
|
Some(value) => Err(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the contents of the cell, initializing it with `f` if the cell
|
||||||
|
/// was empty.
|
||||||
|
///
|
||||||
|
/// Many threads may call `get_or_init` concurrently with different
|
||||||
|
/// initializing functions, but it is guaranteed that only one function
|
||||||
|
/// will be executed.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If `f` panics, the panic is propagated to the caller, and the cell
|
||||||
|
/// remains uninitialized.
|
||||||
|
///
|
||||||
|
/// It is an error to reentrantly initialize the cell from `f`. The
|
||||||
|
/// exact outcome is unspecified. Current implementation deadlocks, but
|
||||||
|
/// this may be changed to a panic in the future.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// let cell = OnceLock::new();
|
||||||
|
/// let value = cell.get_or_init(|| 92);
|
||||||
|
/// assert_eq!(value, &92);
|
||||||
|
/// let value = cell.get_or_init(|| unreachable!());
|
||||||
|
/// assert_eq!(value, &92);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn get_or_init<F>(&self, f: F) -> &T
|
||||||
|
where
|
||||||
|
F: FnOnce() -> T,
|
||||||
|
{
|
||||||
|
match self.get_or_try_init(|| Ok::<T, !>(f())) {
|
||||||
|
Ok(val) => val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the contents of the cell, initializing it with `f` if
|
||||||
|
/// the cell was empty. If the cell was empty and `f` failed, an
|
||||||
|
/// error is returned.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If `f` panics, the panic is propagated to the caller, and
|
||||||
|
/// the cell remains uninitialized.
|
||||||
|
///
|
||||||
|
/// It is an error to reentrantly initialize the cell from `f`.
|
||||||
|
/// The exact outcome is unspecified. Current implementation
|
||||||
|
/// deadlocks, but this may be changed to a panic in the future.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// let cell = OnceLock::new();
|
||||||
|
/// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
|
||||||
|
/// assert!(cell.get().is_none());
|
||||||
|
/// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
|
||||||
|
/// Ok(92)
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(value, Ok(&92));
|
||||||
|
/// assert_eq!(cell.get(), Some(&92))
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<T, E>,
|
||||||
|
{
|
||||||
|
// Fast path check
|
||||||
|
// NOTE: We need to perform an acquire on the state in this method
|
||||||
|
// in order to correctly synchronize `LazyLock::force`. This is
|
||||||
|
// currently done by calling `self.get()`, which in turn calls
|
||||||
|
// `self.is_initialized()`, which in turn performs the acquire.
|
||||||
|
if let Some(value) = self.get() {
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
self.initialize(f)?;
|
||||||
|
|
||||||
|
debug_assert!(self.is_initialized());
|
||||||
|
|
||||||
|
// SAFETY: The inner value has been initialized
|
||||||
|
Ok(unsafe { self.get_unchecked() })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal-only API that gets the contents of the cell, initializing it
|
||||||
|
/// in two steps with `f` and `g` if the cell was empty.
|
||||||
|
///
|
||||||
|
/// `f` is called to construct the value, which is then moved into the cell
|
||||||
|
/// and given as a (pinned) mutable reference to `g` to finish
|
||||||
|
/// initialization.
|
||||||
|
///
|
||||||
|
/// This allows `g` to inspect an manipulate the value after it has been
|
||||||
|
/// moved into its final place in the cell, but before the cell is
|
||||||
|
/// considered initialized.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If `f` or `g` panics, the panic is propagated to the caller, and the
|
||||||
|
/// cell remains uninitialized.
|
||||||
|
///
|
||||||
|
/// With the current implementation, if `g` panics, the value from `f` will
|
||||||
|
/// not be dropped. This should probably be fixed if this is ever used for
|
||||||
|
/// a type where this matters.
|
||||||
|
///
|
||||||
|
/// It is an error to reentrantly initialize the cell from `f`. The exact
|
||||||
|
/// outcome is unspecified. Current implementation deadlocks, but this may
|
||||||
|
/// be changed to a panic in the future.
|
||||||
|
pub(crate) fn get_or_init_pin<F, G>(self: Pin<&Self>, f: F, g: G) -> Pin<&T>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> T,
|
||||||
|
G: FnOnce(Pin<&mut T>),
|
||||||
|
{
|
||||||
|
if let Some(value) = self.get_ref().get() {
|
||||||
|
// SAFETY: The inner value was already initialized, and will not be
|
||||||
|
// moved anymore.
|
||||||
|
return unsafe { Pin::new_unchecked(value) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let slot = &self.value;
|
||||||
|
|
||||||
|
// Ignore poisoning from other threads
|
||||||
|
// If another thread panics, then we'll be able to run our closure
|
||||||
|
self.once.call_once_force(|_| {
|
||||||
|
let value = f();
|
||||||
|
// SAFETY: We use the Once (self.once) to guarantee unique access
|
||||||
|
// to the UnsafeCell (slot).
|
||||||
|
let value: &mut T = unsafe { (&mut *slot.get()).write(value) };
|
||||||
|
// SAFETY: The value has been written to its final place in
|
||||||
|
// self.value. We do not to move it anymore, which we promise here
|
||||||
|
// with a Pin<&mut T>.
|
||||||
|
g(unsafe { Pin::new_unchecked(value) });
|
||||||
|
});
|
||||||
|
|
||||||
|
// SAFETY: The inner value has been initialized, and will not be moved
|
||||||
|
// anymore.
|
||||||
|
unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes the `OnceLock`, returning the wrapped value. Returns
|
||||||
|
/// `None` if the cell was empty.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// let cell: OnceLock<String> = OnceLock::new();
|
||||||
|
/// assert_eq!(cell.into_inner(), None);
|
||||||
|
///
|
||||||
|
/// let cell = OnceLock::new();
|
||||||
|
/// cell.set("hello".to_string()).unwrap();
|
||||||
|
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn into_inner(mut self) -> Option<T> {
|
||||||
|
self.take()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes the value out of this `OnceLock`, moving it back to an uninitialized state.
|
||||||
|
///
|
||||||
|
/// Has no effect and returns `None` if the `OnceLock` hasn't been initialized.
|
||||||
|
///
|
||||||
|
/// Safety is guaranteed by requiring a mutable reference.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// let mut cell: OnceLock<String> = OnceLock::new();
|
||||||
|
/// assert_eq!(cell.take(), None);
|
||||||
|
///
|
||||||
|
/// let mut cell = OnceLock::new();
|
||||||
|
/// cell.set("hello".to_string()).unwrap();
|
||||||
|
/// assert_eq!(cell.take(), Some("hello".to_string()));
|
||||||
|
/// assert_eq!(cell.get(), None);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
pub fn take(&mut self) -> Option<T> {
|
||||||
|
if self.is_initialized() {
|
||||||
|
self.once = Once::new();
|
||||||
|
// SAFETY: `self.value` is initialized and contains a valid `T`.
|
||||||
|
// `self.once` is reset, so `is_initialized()` will be false again
|
||||||
|
// which prevents the value from being read twice.
|
||||||
|
unsafe { Some((&mut *self.value.get()).assume_init_read()) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_initialized(&self) -> bool {
|
||||||
|
self.once.is_completed()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
fn initialize<F, E>(&self, f: F) -> Result<(), E>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<T, E>,
|
||||||
|
{
|
||||||
|
let mut res: Result<(), E> = Ok(());
|
||||||
|
let slot = &self.value;
|
||||||
|
|
||||||
|
// Ignore poisoning from other threads
|
||||||
|
// If another thread panics, then we'll be able to run our closure
|
||||||
|
self.once.call_once_force(|p| {
|
||||||
|
match f() {
|
||||||
|
Ok(value) => {
|
||||||
|
unsafe { (&mut *slot.get()).write(value) };
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
res = Err(e);
|
||||||
|
|
||||||
|
// Treat the underlying `Once` as poisoned since we
|
||||||
|
// failed to initialize our value. Calls
|
||||||
|
p.poison();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The value must be initialized
|
||||||
|
unsafe fn get_unchecked(&self) -> &T {
|
||||||
|
debug_assert!(self.is_initialized());
|
||||||
|
(&*self.value.get()).assume_init_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The value must be initialized
|
||||||
|
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
|
||||||
|
debug_assert!(self.is_initialized());
|
||||||
|
(&mut *self.value.get()).assume_init_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Why do we need `T: Send`?
|
||||||
|
// Thread A creates a `OnceLock` and shares it with
|
||||||
|
// scoped thread B, which fills the cell, which is
|
||||||
|
// then destroyed by A. That is, destructor observes
|
||||||
|
// a sent value.
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
unsafe impl<T: Send> Send for OnceLock<T> {}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
|
||||||
|
impl<T> const Default for OnceLock<T> {
|
||||||
|
/// Creates a new empty cell.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// assert_eq!(OnceLock::<()>::new(), OnceLock::default());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn default() -> OnceLock<T> {
|
||||||
|
OnceLock::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.get() {
|
||||||
|
Some(v) => f.debug_tuple("Once").field(v).finish(),
|
||||||
|
None => f.write_str("Once(Uninit)"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: Clone> Clone for OnceLock<T> {
|
||||||
|
fn clone(&self) -> OnceLock<T> {
|
||||||
|
let cell = Self::new();
|
||||||
|
if let Some(value) = self.get() {
|
||||||
|
match cell.set(value.clone()) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T> From<T> for OnceLock<T> {
|
||||||
|
/// Create a new cell with its contents set to `value`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(once_cell)]
|
||||||
|
///
|
||||||
|
/// use std::sync::OnceLock;
|
||||||
|
///
|
||||||
|
/// # fn main() -> Result<(), i32> {
|
||||||
|
/// let a = OnceLock::from(3);
|
||||||
|
/// let b = OnceLock::new();
|
||||||
|
/// b.set(3)?;
|
||||||
|
/// assert_eq!(a, b);
|
||||||
|
/// Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
let cell = Self::new();
|
||||||
|
match cell.set(value) {
|
||||||
|
Ok(()) => cell,
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: PartialEq> PartialEq for OnceLock<T> {
|
||||||
|
fn eq(&self, other: &OnceLock<T>) -> bool {
|
||||||
|
self.get() == other.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
impl<T: Eq> Eq for OnceLock<T> {}
|
||||||
|
|
||||||
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
|
unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.is_initialized() {
|
||||||
|
// SAFETY: The cell is initialized and being dropped, so it can't
|
||||||
|
// be accessed again. We also don't touch the `T` other than
|
||||||
|
// dropping it, which validates our usage of #[may_dangle].
|
||||||
|
unsafe { (&mut *self.value.get()).assume_init_drop() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
|
@ -1,48 +1,13 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
lazy::{Lazy, SyncLazy, SyncOnceCell},
|
|
||||||
panic,
|
panic,
|
||||||
|
sync::OnceLock,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||||
mpsc::channel,
|
mpsc::channel,
|
||||||
Mutex,
|
|
||||||
},
|
},
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lazy_default() {
|
|
||||||
static CALLED: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
struct Foo(u8);
|
|
||||||
impl Default for Foo {
|
|
||||||
fn default() -> Self {
|
|
||||||
CALLED.fetch_add(1, SeqCst);
|
|
||||||
Foo(42)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let lazy: Lazy<Mutex<Foo>> = <_>::default();
|
|
||||||
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 0);
|
|
||||||
|
|
||||||
assert_eq!(lazy.lock().unwrap().0, 42);
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 1);
|
|
||||||
|
|
||||||
lazy.lock().unwrap().0 = 21;
|
|
||||||
|
|
||||||
assert_eq!(lazy.lock().unwrap().0, 21);
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lazy_poisoning() {
|
|
||||||
let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
|
|
||||||
for _ in 0..2 {
|
|
||||||
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
|
|
||||||
assert!(res.is_err());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
|
fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
|
||||||
thread::spawn(f).join().unwrap()
|
thread::spawn(f).join().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -50,7 +15,7 @@ fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) ->
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||||
fn sync_once_cell() {
|
fn sync_once_cell() {
|
||||||
static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
|
static ONCE_CELL: OnceLock<i32> = OnceLock::new();
|
||||||
|
|
||||||
assert!(ONCE_CELL.get().is_none());
|
assert!(ONCE_CELL.get().is_none());
|
||||||
|
|
||||||
|
@ -65,7 +30,7 @@ fn sync_once_cell() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sync_once_cell_get_mut() {
|
fn sync_once_cell_get_mut() {
|
||||||
let mut c = SyncOnceCell::new();
|
let mut c = OnceLock::new();
|
||||||
assert!(c.get_mut().is_none());
|
assert!(c.get_mut().is_none());
|
||||||
c.set(90).unwrap();
|
c.set(90).unwrap();
|
||||||
*c.get_mut().unwrap() += 2;
|
*c.get_mut().unwrap() += 2;
|
||||||
|
@ -74,7 +39,7 @@ fn sync_once_cell_get_mut() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sync_once_cell_get_unchecked() {
|
fn sync_once_cell_get_unchecked() {
|
||||||
let c = SyncOnceCell::new();
|
let c = OnceLock::new();
|
||||||
c.set(92).unwrap();
|
c.set(92).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
assert_eq!(c.get_unchecked(), &92);
|
assert_eq!(c.get_unchecked(), &92);
|
||||||
|
@ -92,7 +57,7 @@ fn sync_once_cell_drop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = SyncOnceCell::new();
|
let x = OnceLock::new();
|
||||||
spawn_and_wait(move || {
|
spawn_and_wait(move || {
|
||||||
x.get_or_init(|| Dropper);
|
x.get_or_init(|| Dropper);
|
||||||
assert_eq!(DROP_CNT.load(SeqCst), 0);
|
assert_eq!(DROP_CNT.load(SeqCst), 0);
|
||||||
|
@ -104,13 +69,13 @@ fn sync_once_cell_drop() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sync_once_cell_drop_empty() {
|
fn sync_once_cell_drop_empty() {
|
||||||
let x = SyncOnceCell::<String>::new();
|
let x = OnceLock::<String>::new();
|
||||||
drop(x);
|
drop(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn clone() {
|
fn clone() {
|
||||||
let s = SyncOnceCell::new();
|
let s = OnceLock::new();
|
||||||
let c = s.clone();
|
let c = s.clone();
|
||||||
assert!(c.get().is_none());
|
assert!(c.get().is_none());
|
||||||
|
|
||||||
|
@ -121,7 +86,7 @@ fn clone() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_or_try_init() {
|
fn get_or_try_init() {
|
||||||
let cell: SyncOnceCell<String> = SyncOnceCell::new();
|
let cell: OnceLock<String> = OnceLock::new();
|
||||||
assert!(cell.get().is_none());
|
assert!(cell.get().is_none());
|
||||||
|
|
||||||
let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
|
let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
|
||||||
|
@ -137,122 +102,32 @@ fn get_or_try_init() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_impl() {
|
fn from_impl() {
|
||||||
assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
|
assert_eq!(OnceLock::from("value").get(), Some(&"value"));
|
||||||
assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
|
assert_ne!(OnceLock::from("foo").get(), Some(&"bar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn partialeq_impl() {
|
fn partialeq_impl() {
|
||||||
assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
|
assert!(OnceLock::from("value") == OnceLock::from("value"));
|
||||||
assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
|
assert!(OnceLock::from("foo") != OnceLock::from("bar"));
|
||||||
|
|
||||||
assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
|
assert!(OnceLock::<String>::new() == OnceLock::new());
|
||||||
assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
|
assert!(OnceLock::<String>::new() != OnceLock::from("value".to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn into_inner() {
|
fn into_inner() {
|
||||||
let cell: SyncOnceCell<String> = SyncOnceCell::new();
|
let cell: OnceLock<String> = OnceLock::new();
|
||||||
assert_eq!(cell.into_inner(), None);
|
assert_eq!(cell.into_inner(), None);
|
||||||
let cell = SyncOnceCell::new();
|
let cell = OnceLock::new();
|
||||||
cell.set("hello".to_string()).unwrap();
|
cell.set("hello".to_string()).unwrap();
|
||||||
assert_eq!(cell.into_inner(), Some("hello".to_string()));
|
assert_eq!(cell.into_inner(), Some("hello".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
|
||||||
fn sync_lazy_new() {
|
|
||||||
static CALLED: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
|
|
||||||
CALLED.fetch_add(1, SeqCst);
|
|
||||||
92
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 0);
|
|
||||||
|
|
||||||
spawn_and_wait(|| {
|
|
||||||
let y = *SYNC_LAZY - 30;
|
|
||||||
assert_eq!(y, 62);
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
let y = *SYNC_LAZY - 30;
|
|
||||||
assert_eq!(y, 62);
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sync_lazy_default() {
|
|
||||||
static CALLED: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
struct Foo(u8);
|
|
||||||
impl Default for Foo {
|
|
||||||
fn default() -> Self {
|
|
||||||
CALLED.fetch_add(1, SeqCst);
|
|
||||||
Foo(42)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
|
|
||||||
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 0);
|
|
||||||
|
|
||||||
assert_eq!(lazy.lock().unwrap().0, 42);
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 1);
|
|
||||||
|
|
||||||
lazy.lock().unwrap().0 = 21;
|
|
||||||
|
|
||||||
assert_eq!(lazy.lock().unwrap().0, 21);
|
|
||||||
assert_eq!(CALLED.load(SeqCst), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
|
||||||
fn static_sync_lazy() {
|
|
||||||
static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
|
|
||||||
let mut xs = Vec::new();
|
|
||||||
xs.push(1);
|
|
||||||
xs.push(2);
|
|
||||||
xs.push(3);
|
|
||||||
xs
|
|
||||||
});
|
|
||||||
|
|
||||||
spawn_and_wait(|| {
|
|
||||||
assert_eq!(&*XS, &vec![1, 2, 3]);
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(&*XS, &vec![1, 2, 3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn static_sync_lazy_via_fn() {
|
|
||||||
fn xs() -> &'static Vec<i32> {
|
|
||||||
static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
|
|
||||||
XS.get_or_init(|| {
|
|
||||||
let mut xs = Vec::new();
|
|
||||||
xs.push(1);
|
|
||||||
xs.push(2);
|
|
||||||
xs.push(3);
|
|
||||||
xs
|
|
||||||
})
|
|
||||||
}
|
|
||||||
assert_eq!(xs(), &vec![1, 2, 3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sync_lazy_poisoning() {
|
|
||||||
let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
|
|
||||||
for _ in 0..2 {
|
|
||||||
let res = panic::catch_unwind(|| x.len());
|
|
||||||
assert!(res.is_err());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn is_sync_send() {
|
fn is_sync_send() {
|
||||||
fn assert_traits<T: Send + Sync>() {}
|
fn assert_traits<T: Send + Sync>() {}
|
||||||
assert_traits::<SyncOnceCell<String>>();
|
assert_traits::<OnceLock<String>>();
|
||||||
assert_traits::<SyncLazy<String>>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -261,7 +136,7 @@ fn eval_once_macro() {
|
||||||
(|| -> $ty:ty {
|
(|| -> $ty:ty {
|
||||||
$($body:tt)*
|
$($body:tt)*
|
||||||
}) => {{
|
}) => {{
|
||||||
static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
|
static ONCE_CELL: OnceLock<$ty> = OnceLock::new();
|
||||||
fn init() -> $ty {
|
fn init() -> $ty {
|
||||||
$($body)*
|
$($body)*
|
||||||
}
|
}
|
||||||
|
@ -285,7 +160,7 @@ fn eval_once_macro() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||||
fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
|
fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
|
||||||
static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
|
static ONCE_CELL: OnceLock<String> = OnceLock::new();
|
||||||
|
|
||||||
let n_readers = 10;
|
let n_readers = 10;
|
||||||
let n_writers = 3;
|
let n_writers = 3;
|
||||||
|
@ -320,7 +195,7 @@ fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dropck() {
|
fn dropck() {
|
||||||
let cell = SyncOnceCell::new();
|
let cell = OnceLock::new();
|
||||||
{
|
{
|
||||||
let s = String::new();
|
let s = String::new();
|
||||||
cell.set(&s).unwrap();
|
cell.set(&s).unwrap();
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
use crate::cmp;
|
use crate::cmp;
|
||||||
use crate::io::{self, IoSlice, IoSliceMut, Read};
|
use crate::io::{self, IoSlice, IoSliceMut, Read};
|
||||||
use crate::lazy::SyncOnceCell;
|
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::net::{Shutdown, SocketAddr};
|
use crate::net::{Shutdown, SocketAddr};
|
||||||
use crate::os::windows::io::{
|
use crate::os::windows::io::{
|
||||||
AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
|
AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
|
||||||
};
|
};
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
|
use crate::sync::OnceLock;
|
||||||
use crate::sys;
|
use crate::sys;
|
||||||
use crate::sys::c;
|
use crate::sys::c;
|
||||||
use crate::sys_common::net;
|
use crate::sys_common::net;
|
||||||
|
@ -29,7 +29,7 @@ pub mod netc {
|
||||||
|
|
||||||
pub struct Socket(OwnedSocket);
|
pub struct Socket(OwnedSocket);
|
||||||
|
|
||||||
static WSA_CLEANUP: SyncOnceCell<unsafe extern "system" fn() -> i32> = SyncOnceCell::new();
|
static WSA_CLEANUP: OnceLock<unsafe extern "system" fn() -> i32> = OnceLock::new();
|
||||||
|
|
||||||
/// Checks whether the Windows socket interface has been started already, and
|
/// Checks whether the Windows socket interface has been started already, and
|
||||||
/// if not, starts it.
|
/// if not, starts it.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::lazy;
|
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
|
use crate::sync;
|
||||||
use crate::sys::c;
|
use crate::sys::c;
|
||||||
|
|
||||||
/// The kinds of HashMap RNG that may be available
|
/// The kinds of HashMap RNG that may be available
|
||||||
|
@ -28,7 +28,7 @@ fn get_hashmap_rng() -> HashMapRng {
|
||||||
// Assume that if the preferred RNG is broken the first time we use it, it likely means
|
// Assume that if the preferred RNG is broken the first time we use it, it likely means
|
||||||
// that: the DLL has failed to load, there is no point to calling it over-and-over again,
|
// that: the DLL has failed to load, there is no point to calling it over-and-over again,
|
||||||
// and we should cache the result
|
// and we should cache the result
|
||||||
static VALUE: lazy::SyncOnceCell<HashMapRng> = lazy::SyncOnceCell::new();
|
static VALUE: sync::OnceLock<HashMapRng> = sync::OnceLock::new();
|
||||||
*VALUE.get_or_init(choose_hashmap_rng)
|
*VALUE.get_or_init(choose_hashmap_rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::lazy::SyncOnceCell as OnceCell;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::OnceLock as OnceCell;
|
||||||
use std::{cmp, fmt, iter};
|
use std::{cmp, fmt, iter};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
|
|
|
@ -21,9 +21,9 @@ use rustc_span::symbol::sym;
|
||||||
use rustc_span::{source_map, Span, Symbol};
|
use rustc_span::{source_map, Span, Symbol};
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::lazy::SyncLazy;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use crate::clean::inline::build_external_trait;
|
use crate::clean::inline::build_external_trait;
|
||||||
use crate::clean::{self, ItemId, TraitWithExtraInfo};
|
use crate::clean::{self, ItemId, TraitWithExtraInfo};
|
||||||
|
@ -293,8 +293,8 @@ pub(crate) fn create_config(
|
||||||
providers.typeck_item_bodies = |_, _| {};
|
providers.typeck_item_bodies = |_, _| {};
|
||||||
// hack so that `used_trait_imports` won't try to call typeck
|
// hack so that `used_trait_imports` won't try to call typeck
|
||||||
providers.used_trait_imports = |_, _| {
|
providers.used_trait_imports = |_, _| {
|
||||||
static EMPTY_SET: SyncLazy<FxHashSet<LocalDefId>> =
|
static EMPTY_SET: LazyLock<FxHashSet<LocalDefId>> =
|
||||||
SyncLazy::new(FxHashSet::default);
|
LazyLock::new(FxHashSet::default);
|
||||||
&EMPTY_SET
|
&EMPTY_SET
|
||||||
};
|
};
|
||||||
// In case typeck does end up being called, don't ICE in case there were name resolution errors
|
// In case typeck does end up being called, don't ICE in case there were name resolution errors
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::fmt::Write;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::{self, BufReader};
|
use std::io::{self, BufReader};
|
||||||
use std::lazy::SyncLazy as Lazy;
|
|
||||||
use std::path::{Component, Path, PathBuf};
|
use std::path::{Component, Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::LazyLock as Lazy;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_data_structures::flock;
|
use rustc_data_structures::flock;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rustc_lint::LintStore;
|
||||||
use rustc_lint_defs::{declare_tool_lint, Lint, LintId};
|
use rustc_lint_defs::{declare_tool_lint, Lint, LintId};
|
||||||
use rustc_session::{lint, Session};
|
use rustc_session::{lint, Session};
|
||||||
|
|
||||||
use std::lazy::SyncLazy as Lazy;
|
use std::sync::LazyLock as Lazy;
|
||||||
|
|
||||||
/// This function is used to setup the lint initialization. By default, in rustdoc, everything
|
/// This function is used to setup the lint initialization. By default, in rustdoc, everything
|
||||||
/// is "allowed". Depending if we run in test mode or not, we want some of them to be at their
|
/// is "allowed". Depending if we run in test mode or not, we want some of them to be at their
|
||||||
|
|
|
@ -9,8 +9,8 @@ use core::ops::Range;
|
||||||
use pulldown_cmark::{Event, Parser, Tag};
|
use pulldown_cmark::{Event, Parser, Tag};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use std::lazy::SyncLazy;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub(crate) const CHECK_BARE_URLS: Pass = Pass {
|
pub(crate) const CHECK_BARE_URLS: Pass = Pass {
|
||||||
name: "check-bare-urls",
|
name: "check-bare-urls",
|
||||||
|
@ -18,7 +18,7 @@ pub(crate) const CHECK_BARE_URLS: Pass = Pass {
|
||||||
description: "detects URLs that are not hyperlinks",
|
description: "detects URLs that are not hyperlinks",
|
||||||
};
|
};
|
||||||
|
|
||||||
static URL_REGEX: SyncLazy<Regex> = SyncLazy::new(|| {
|
static URL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
Regex::new(concat!(
|
Regex::new(concat!(
|
||||||
r"https?://", // url scheme
|
r"https?://", // url scheme
|
||||||
r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
|
r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
#![feature(once_cell)]
|
#![feature(once_cell)]
|
||||||
|
|
||||||
use std::{io::ErrorKind, lazy::SyncOnceCell, thread::{self, Builder, ThreadId}};
|
use std::{
|
||||||
|
io::ErrorKind,
|
||||||
|
sync::OnceLock,
|
||||||
|
thread::{self, Builder, ThreadId},
|
||||||
|
};
|
||||||
|
|
||||||
static THREAD_ID: SyncOnceCell<ThreadId> = SyncOnceCell::new();
|
static THREAD_ID: OnceLock<ThreadId> = OnceLock::new();
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn spawn_thread_would_block() {
|
fn spawn_thread_would_block() {
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
use crate::cargo_clippy_path;
|
use crate::cargo_clippy_path;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::lazy::SyncLazy;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::LazyLock;
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> =
|
static CLIPPY_BUILD_TIME: LazyLock<Option<std::time::SystemTime>> =
|
||||||
SyncLazy::new(|| cargo_clippy_path().metadata().ok()?.modified().ok());
|
LazyLock::new(|| cargo_clippy_path().metadata().ok()?.modified().ok());
|
||||||
|
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
|
|
@ -64,7 +64,7 @@ pub use self::hir_utils::{
|
||||||
|
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
use std::lazy::SyncOnceCell;
|
use std::sync::OnceLock;
|
||||||
use std::sync::{Mutex, MutexGuard};
|
use std::sync::{Mutex, MutexGuard};
|
||||||
|
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
|
@ -2080,7 +2080,7 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new();
|
static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = OnceLock::new();
|
||||||
|
|
||||||
fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
|
fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
|
||||||
let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
|
let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
|
||||||
|
|
|
@ -21,11 +21,11 @@ use rustc_tools_util::VersionInfo;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::lazy::SyncLazy;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::panic;
|
use std::panic;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{exit, Command};
|
use std::process::{exit, Command};
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
|
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
|
||||||
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
|
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
|
||||||
|
@ -152,7 +152,7 @@ You can use tool lints to allow or deny lints from your code, eg.:
|
||||||
|
|
||||||
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
|
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
|
||||||
|
|
||||||
static ICE_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> = SyncLazy::new(|| {
|
static ICE_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> = LazyLock::new(|| {
|
||||||
let hook = panic::take_hook();
|
let hook = panic::take_hook();
|
||||||
panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
|
panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
|
||||||
hook
|
hook
|
||||||
|
@ -219,7 +219,7 @@ fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<Pat
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
rustc_driver::init_rustc_env_logger();
|
rustc_driver::init_rustc_env_logger();
|
||||||
SyncLazy::force(&ICE_HOOK);
|
LazyLock::force(&ICE_HOOK);
|
||||||
exit(rustc_driver::catch_with_exit_code(move || {
|
exit(rustc_driver::catch_with_exit_code(move || {
|
||||||
let mut orig_args: Vec<String> = env::args().collect();
|
let mut orig_args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ use std::env::{self, remove_var, set_var, var_os};
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::lazy::SyncLazy;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::LazyLock;
|
||||||
use test_utils::IS_RUSTC_TEST_SUITE;
|
use test_utils::IS_RUSTC_TEST_SUITE;
|
||||||
|
|
||||||
mod test_utils;
|
mod test_utils;
|
||||||
|
@ -69,7 +69,7 @@ extern crate tokio;
|
||||||
/// dependencies must be added to Cargo.toml at the project root. Test
|
/// dependencies must be added to Cargo.toml at the project root. Test
|
||||||
/// dependencies that are not *directly* used by this test module require an
|
/// dependencies that are not *directly* used by this test module require an
|
||||||
/// `extern crate` declaration.
|
/// `extern crate` declaration.
|
||||||
static EXTERN_FLAGS: SyncLazy<String> = SyncLazy::new(|| {
|
static EXTERN_FLAGS: LazyLock<String> = LazyLock::new(|| {
|
||||||
let current_exe_depinfo = {
|
let current_exe_depinfo = {
|
||||||
let mut path = env::current_exe().unwrap();
|
let mut path = env::current_exe().unwrap();
|
||||||
path.set_extension("d");
|
path.set_extension("d");
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#![allow(dead_code)] // see https://github.com/rust-lang/rust/issues/46379
|
#![allow(dead_code)] // see https://github.com/rust-lang/rust/issues/46379
|
||||||
|
|
||||||
use std::lazy::SyncLazy;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub static CARGO_CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| {
|
pub static CARGO_CLIPPY_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||||
let mut path = std::env::current_exe().unwrap();
|
let mut path = std::env::current_exe().unwrap();
|
||||||
assert!(path.pop()); // deps
|
assert!(path.pop()); // deps
|
||||||
path.set_file_name("cargo-clippy");
|
path.set_file_name("cargo-clippy");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue