mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
port from lazycell
This commit is contained in:
parent
742a111df3
commit
c7a1dde3fd
@ -51,6 +51,7 @@
|
|||||||
|
|
||||||
use crate::util::cache_lock::{CacheLock, CacheLockMode, CacheLocker};
|
use crate::util::cache_lock::{CacheLock, CacheLockMode, CacheLocker};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::cell::OnceCell;
|
||||||
use std::cell::{RefCell, RefMut};
|
use std::cell::{RefCell, RefMut};
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@ -74,6 +75,7 @@ use crate::core::{CliUnstable, Shell, SourceId, Workspace, WorkspaceRootConfig,
|
|||||||
use crate::ops::RegistryCredentialConfig;
|
use crate::ops::RegistryCredentialConfig;
|
||||||
use crate::sources::CRATES_IO_INDEX;
|
use crate::sources::CRATES_IO_INDEX;
|
||||||
use crate::sources::CRATES_IO_REGISTRY;
|
use crate::sources::CRATES_IO_REGISTRY;
|
||||||
|
use crate::util::OnceExt as _;
|
||||||
use crate::util::errors::CargoResult;
|
use crate::util::errors::CargoResult;
|
||||||
use crate::util::network::http::configure_http_handle;
|
use crate::util::network::http::configure_http_handle;
|
||||||
use crate::util::network::http::http_handle;
|
use crate::util::network::http::http_handle;
|
||||||
@ -85,7 +87,6 @@ use cargo_util::paths;
|
|||||||
use cargo_util_schemas::manifest::RegistryName;
|
use cargo_util_schemas::manifest::RegistryName;
|
||||||
use curl::easy::Easy;
|
use curl::easy::Easy;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lazycell::LazyCell;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::de::IntoDeserializer as _;
|
use serde::de::IntoDeserializer as _;
|
||||||
use serde_untagged::UntaggedEnumVisitor;
|
use serde_untagged::UntaggedEnumVisitor;
|
||||||
@ -168,9 +169,9 @@ pub struct GlobalContext {
|
|||||||
/// Information about how to write messages to the shell
|
/// Information about how to write messages to the shell
|
||||||
shell: RefCell<Shell>,
|
shell: RefCell<Shell>,
|
||||||
/// A collection of configuration options
|
/// A collection of configuration options
|
||||||
values: LazyCell<HashMap<String, ConfigValue>>,
|
values: OnceCell<HashMap<String, ConfigValue>>,
|
||||||
/// A collection of configuration options from the credentials file
|
/// A collection of configuration options from the credentials file
|
||||||
credential_values: LazyCell<HashMap<String, ConfigValue>>,
|
credential_values: OnceCell<HashMap<String, ConfigValue>>,
|
||||||
/// CLI config values, passed in via `configure`.
|
/// CLI config values, passed in via `configure`.
|
||||||
cli_config: Option<Vec<String>>,
|
cli_config: Option<Vec<String>>,
|
||||||
/// The current working directory of cargo
|
/// The current working directory of cargo
|
||||||
@ -178,9 +179,9 @@ pub struct GlobalContext {
|
|||||||
/// Directory where config file searching should stop (inclusive).
|
/// Directory where config file searching should stop (inclusive).
|
||||||
search_stop_path: Option<PathBuf>,
|
search_stop_path: Option<PathBuf>,
|
||||||
/// The location of the cargo executable (path to current process)
|
/// The location of the cargo executable (path to current process)
|
||||||
cargo_exe: LazyCell<PathBuf>,
|
cargo_exe: OnceCell<PathBuf>,
|
||||||
/// The location of the rustdoc executable
|
/// The location of the rustdoc executable
|
||||||
rustdoc: LazyCell<PathBuf>,
|
rustdoc: OnceCell<PathBuf>,
|
||||||
/// Whether we are printing extra verbose messages
|
/// Whether we are printing extra verbose messages
|
||||||
extra_verbose: bool,
|
extra_verbose: bool,
|
||||||
/// `frozen` is the same as `locked`, but additionally will not access the
|
/// `frozen` is the same as `locked`, but additionally will not access the
|
||||||
@ -199,9 +200,9 @@ pub struct GlobalContext {
|
|||||||
/// Cli flags of the form "-Z something"
|
/// Cli flags of the form "-Z something"
|
||||||
unstable_flags_cli: Option<Vec<String>>,
|
unstable_flags_cli: Option<Vec<String>>,
|
||||||
/// A handle on curl easy mode for http calls
|
/// A handle on curl easy mode for http calls
|
||||||
easy: LazyCell<RefCell<Easy>>,
|
easy: OnceCell<RefCell<Easy>>,
|
||||||
/// Cache of the `SourceId` for crates.io
|
/// Cache of the `SourceId` for crates.io
|
||||||
crates_io_source_id: LazyCell<SourceId>,
|
crates_io_source_id: OnceCell<SourceId>,
|
||||||
/// If false, don't cache `rustc --version --verbose` invocations
|
/// If false, don't cache `rustc --version --verbose` invocations
|
||||||
cache_rustc_info: bool,
|
cache_rustc_info: bool,
|
||||||
/// Creation time of this config, used to output the total build time
|
/// Creation time of this config, used to output the total build time
|
||||||
@ -211,23 +212,23 @@ pub struct GlobalContext {
|
|||||||
/// Environment variable snapshot.
|
/// Environment variable snapshot.
|
||||||
env: Env,
|
env: Env,
|
||||||
/// Tracks which sources have been updated to avoid multiple updates.
|
/// Tracks which sources have been updated to avoid multiple updates.
|
||||||
updated_sources: LazyCell<RefCell<HashSet<SourceId>>>,
|
updated_sources: OnceCell<RefCell<HashSet<SourceId>>>,
|
||||||
/// Cache of credentials from configuration or credential providers.
|
/// Cache of credentials from configuration or credential providers.
|
||||||
/// Maps from url to credential value.
|
/// Maps from url to credential value.
|
||||||
credential_cache: LazyCell<RefCell<HashMap<CanonicalUrl, CredentialCacheValue>>>,
|
credential_cache: OnceCell<RefCell<HashMap<CanonicalUrl, CredentialCacheValue>>>,
|
||||||
/// Cache of registry config from the `[registries]` table.
|
/// Cache of registry config from the `[registries]` table.
|
||||||
registry_config: LazyCell<RefCell<HashMap<SourceId, Option<RegistryConfig>>>>,
|
registry_config: OnceCell<RefCell<HashMap<SourceId, Option<RegistryConfig>>>>,
|
||||||
/// Locks on the package and index caches.
|
/// Locks on the package and index caches.
|
||||||
package_cache_lock: CacheLocker,
|
package_cache_lock: CacheLocker,
|
||||||
/// Cached configuration parsed by Cargo
|
/// Cached configuration parsed by Cargo
|
||||||
http_config: LazyCell<CargoHttpConfig>,
|
http_config: OnceCell<CargoHttpConfig>,
|
||||||
future_incompat_config: LazyCell<CargoFutureIncompatConfig>,
|
future_incompat_config: OnceCell<CargoFutureIncompatConfig>,
|
||||||
net_config: LazyCell<CargoNetConfig>,
|
net_config: OnceCell<CargoNetConfig>,
|
||||||
build_config: LazyCell<CargoBuildConfig>,
|
build_config: OnceCell<CargoBuildConfig>,
|
||||||
target_cfgs: LazyCell<Vec<(String, TargetCfgConfig)>>,
|
target_cfgs: OnceCell<Vec<(String, TargetCfgConfig)>>,
|
||||||
doc_extern_map: LazyCell<RustdocExternMap>,
|
doc_extern_map: OnceCell<RustdocExternMap>,
|
||||||
progress_config: ProgressConfig,
|
progress_config: ProgressConfig,
|
||||||
env_config: LazyCell<Arc<HashMap<String, OsString>>>,
|
env_config: OnceCell<Arc<HashMap<String, OsString>>>,
|
||||||
/// This should be false if:
|
/// This should be false if:
|
||||||
/// - this is an artifact of the rustc distribution process for "stable" or for "beta"
|
/// - this is an artifact of the rustc distribution process for "stable" or for "beta"
|
||||||
/// - this is an `#[test]` that does not opt in with `enable_nightly_features`
|
/// - this is an `#[test]` that does not opt in with `enable_nightly_features`
|
||||||
@ -247,10 +248,10 @@ pub struct GlobalContext {
|
|||||||
/// `WorkspaceRootConfigs` that have been found
|
/// `WorkspaceRootConfigs` that have been found
|
||||||
pub ws_roots: RefCell<HashMap<PathBuf, WorkspaceRootConfig>>,
|
pub ws_roots: RefCell<HashMap<PathBuf, WorkspaceRootConfig>>,
|
||||||
/// The global cache tracker is a database used to track disk cache usage.
|
/// The global cache tracker is a database used to track disk cache usage.
|
||||||
global_cache_tracker: LazyCell<RefCell<GlobalCacheTracker>>,
|
global_cache_tracker: OnceCell<RefCell<GlobalCacheTracker>>,
|
||||||
/// A cache of modifications to make to [`GlobalContext::global_cache_tracker`],
|
/// A cache of modifications to make to [`GlobalContext::global_cache_tracker`],
|
||||||
/// saved to disk in a batch to improve performance.
|
/// saved to disk in a batch to improve performance.
|
||||||
deferred_global_last_use: LazyCell<RefCell<DeferredGlobalLastUse>>,
|
deferred_global_last_use: OnceCell<RefCell<DeferredGlobalLastUse>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalContext {
|
impl GlobalContext {
|
||||||
@ -286,11 +287,11 @@ impl GlobalContext {
|
|||||||
shell: RefCell::new(shell),
|
shell: RefCell::new(shell),
|
||||||
cwd,
|
cwd,
|
||||||
search_stop_path: None,
|
search_stop_path: None,
|
||||||
values: LazyCell::new(),
|
values: OnceCell::new(),
|
||||||
credential_values: LazyCell::new(),
|
credential_values: OnceCell::new(),
|
||||||
cli_config: None,
|
cli_config: None,
|
||||||
cargo_exe: LazyCell::new(),
|
cargo_exe: OnceCell::new(),
|
||||||
rustdoc: LazyCell::new(),
|
rustdoc: OnceCell::new(),
|
||||||
extra_verbose: false,
|
extra_verbose: false,
|
||||||
frozen: false,
|
frozen: false,
|
||||||
locked: false,
|
locked: false,
|
||||||
@ -304,28 +305,28 @@ impl GlobalContext {
|
|||||||
},
|
},
|
||||||
unstable_flags: CliUnstable::default(),
|
unstable_flags: CliUnstable::default(),
|
||||||
unstable_flags_cli: None,
|
unstable_flags_cli: None,
|
||||||
easy: LazyCell::new(),
|
easy: OnceCell::new(),
|
||||||
crates_io_source_id: LazyCell::new(),
|
crates_io_source_id: OnceCell::new(),
|
||||||
cache_rustc_info,
|
cache_rustc_info,
|
||||||
creation_time: Instant::now(),
|
creation_time: Instant::now(),
|
||||||
target_dir: None,
|
target_dir: None,
|
||||||
env,
|
env,
|
||||||
updated_sources: LazyCell::new(),
|
updated_sources: OnceCell::new(),
|
||||||
credential_cache: LazyCell::new(),
|
credential_cache: OnceCell::new(),
|
||||||
registry_config: LazyCell::new(),
|
registry_config: OnceCell::new(),
|
||||||
package_cache_lock: CacheLocker::new(),
|
package_cache_lock: CacheLocker::new(),
|
||||||
http_config: LazyCell::new(),
|
http_config: OnceCell::new(),
|
||||||
future_incompat_config: LazyCell::new(),
|
future_incompat_config: OnceCell::new(),
|
||||||
net_config: LazyCell::new(),
|
net_config: OnceCell::new(),
|
||||||
build_config: LazyCell::new(),
|
build_config: OnceCell::new(),
|
||||||
target_cfgs: LazyCell::new(),
|
target_cfgs: OnceCell::new(),
|
||||||
doc_extern_map: LazyCell::new(),
|
doc_extern_map: OnceCell::new(),
|
||||||
progress_config: ProgressConfig::default(),
|
progress_config: ProgressConfig::default(),
|
||||||
env_config: LazyCell::new(),
|
env_config: OnceCell::new(),
|
||||||
nightly_features_allowed: matches!(&*features::channel(), "nightly" | "dev"),
|
nightly_features_allowed: matches!(&*features::channel(), "nightly" | "dev"),
|
||||||
ws_roots: RefCell::new(HashMap::new()),
|
ws_roots: RefCell::new(HashMap::new()),
|
||||||
global_cache_tracker: LazyCell::new(),
|
global_cache_tracker: OnceCell::new(),
|
||||||
deferred_global_last_use: LazyCell::new(),
|
deferred_global_last_use: OnceCell::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,21 +527,21 @@ impl GlobalContext {
|
|||||||
/// Which package sources have been updated, used to ensure it is only done once.
|
/// Which package sources have been updated, used to ensure it is only done once.
|
||||||
pub fn updated_sources(&self) -> RefMut<'_, HashSet<SourceId>> {
|
pub fn updated_sources(&self) -> RefMut<'_, HashSet<SourceId>> {
|
||||||
self.updated_sources
|
self.updated_sources
|
||||||
.borrow_with(|| RefCell::new(HashSet::new()))
|
.get_or_init(|| RefCell::new(HashSet::new()))
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cached credentials from credential providers or configuration.
|
/// Cached credentials from credential providers or configuration.
|
||||||
pub fn credential_cache(&self) -> RefMut<'_, HashMap<CanonicalUrl, CredentialCacheValue>> {
|
pub fn credential_cache(&self) -> RefMut<'_, HashMap<CanonicalUrl, CredentialCacheValue>> {
|
||||||
self.credential_cache
|
self.credential_cache
|
||||||
.borrow_with(|| RefCell::new(HashMap::new()))
|
.get_or_init(|| RefCell::new(HashMap::new()))
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cache of already parsed registries from the `[registries]` table.
|
/// Cache of already parsed registries from the `[registries]` table.
|
||||||
pub(crate) fn registry_config(&self) -> RefMut<'_, HashMap<SourceId, Option<RegistryConfig>>> {
|
pub(crate) fn registry_config(&self) -> RefMut<'_, HashMap<SourceId, Option<RegistryConfig>>> {
|
||||||
self.registry_config
|
self.registry_config
|
||||||
.borrow_with(|| RefCell::new(HashMap::new()))
|
.get_or_init(|| RefCell::new(HashMap::new()))
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,18 +562,15 @@ impl GlobalContext {
|
|||||||
/// using this if possible.
|
/// using this if possible.
|
||||||
pub fn values_mut(&mut self) -> CargoResult<&mut HashMap<String, ConfigValue>> {
|
pub fn values_mut(&mut self) -> CargoResult<&mut HashMap<String, ConfigValue>> {
|
||||||
let _ = self.values()?;
|
let _ = self.values()?;
|
||||||
Ok(self
|
Ok(self.values.get_mut().expect("already loaded config values"))
|
||||||
.values
|
|
||||||
.borrow_mut()
|
|
||||||
.expect("already loaded config values"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this is used by RLS, not Cargo.
|
// Note: this is used by RLS, not Cargo.
|
||||||
pub fn set_values(&self, values: HashMap<String, ConfigValue>) -> CargoResult<()> {
|
pub fn set_values(&self, values: HashMap<String, ConfigValue>) -> CargoResult<()> {
|
||||||
if self.values.borrow().is_some() {
|
if self.values.get().is_some() {
|
||||||
bail!("config values already found")
|
bail!("config values already found")
|
||||||
}
|
}
|
||||||
match self.values.fill(values) {
|
match self.values.set(values) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(_) => bail!("could not fill values"),
|
Err(_) => bail!("could not fill values"),
|
||||||
}
|
}
|
||||||
@ -741,7 +739,7 @@ impl GlobalContext {
|
|||||||
/// This does NOT look at environment variables. See `get_cv_with_env` for
|
/// This does NOT look at environment variables. See `get_cv_with_env` for
|
||||||
/// a variant that supports environment variables.
|
/// a variant that supports environment variables.
|
||||||
fn get_cv(&self, key: &ConfigKey) -> CargoResult<Option<ConfigValue>> {
|
fn get_cv(&self, key: &ConfigKey) -> CargoResult<Option<ConfigValue>> {
|
||||||
if let Some(vals) = self.credential_values.borrow() {
|
if let Some(vals) = self.credential_values.get() {
|
||||||
let val = self.get_cv_helper(key, vals)?;
|
let val = self.get_cv_helper(key, vals)?;
|
||||||
if val.is_some() {
|
if val.is_some() {
|
||||||
return Ok(val);
|
return Ok(val);
|
||||||
@ -1802,7 +1800,7 @@ impl GlobalContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.credential_values
|
self.credential_values
|
||||||
.fill(credential_values)
|
.set(credential_values)
|
||||||
.expect("was not filled at beginning of the function");
|
.expect("was not filled at beginning of the function");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ pub use self::into_url::IntoUrl;
|
|||||||
pub use self::into_url_with_base::IntoUrlWithBase;
|
pub use self::into_url_with_base::IntoUrlWithBase;
|
||||||
pub(crate) use self::io::LimitErrorReader;
|
pub(crate) use self::io::LimitErrorReader;
|
||||||
pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted};
|
pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted};
|
||||||
|
pub use self::once::OnceExt;
|
||||||
pub use self::progress::{Progress, ProgressStyle};
|
pub use self::progress::{Progress, ProgressStyle};
|
||||||
pub use self::queue::Queue;
|
pub use self::queue::Queue;
|
||||||
pub use self::rustc::Rustc;
|
pub use self::rustc::Rustc;
|
||||||
@ -56,6 +57,7 @@ pub mod lints;
|
|||||||
mod lockserver;
|
mod lockserver;
|
||||||
pub mod machine_message;
|
pub mod machine_message;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
|
mod once;
|
||||||
mod progress;
|
mod progress;
|
||||||
mod queue;
|
mod queue;
|
||||||
pub mod restricted_names;
|
pub mod restricted_names;
|
||||||
|
90
src/cargo/util/once.rs
Normal file
90
src/cargo/util/once.rs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
//! Extension functions for [`std::sync::OnceLock`] / [`std::cell::OnceCell`]
|
||||||
|
//!
|
||||||
|
//! This adds polyfills for functionality in `lazycell` that is not stable within `std`.
|
||||||
|
|
||||||
|
pub trait OnceExt {
|
||||||
|
type T;
|
||||||
|
|
||||||
|
/// This might run `f` multiple times if different threads start initializing at once.
|
||||||
|
fn try_borrow_with<F, E>(&self, f: F) -> Result<&Self::T, E>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<Self::T, E>;
|
||||||
|
|
||||||
|
fn replace(&mut self, new_value: Self::T) -> Option<Self::T>;
|
||||||
|
|
||||||
|
fn filled(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> OnceExt for std::sync::OnceLock<T> {
|
||||||
|
type T = T;
|
||||||
|
|
||||||
|
fn try_borrow_with<F, E>(&self, f: F) -> Result<&T, E>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<T, E>,
|
||||||
|
{
|
||||||
|
if let Some(value) = self.get() {
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not how the unstable `OnceLock::get_or_try_init` works. That only starts `f` if
|
||||||
|
// no other `f` is executing and the value is not initialized. However, correctly implementing that is
|
||||||
|
// hard (one has properly handle panics in `f`) and not doable with the stable API of `OnceLock`.
|
||||||
|
let value = f()?;
|
||||||
|
// Another thread might have initialized `self` since we checked that `self.get()` returns `None`. If this is the case, `self.set()`
|
||||||
|
// returns an error. We ignore it and return the value set by the other
|
||||||
|
// thread.
|
||||||
|
let _ = self.set(value);
|
||||||
|
Ok(self.get().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace(&mut self, new_value: T) -> Option<T> {
|
||||||
|
if let Some(value) = self.get_mut() {
|
||||||
|
Some(std::mem::replace(value, new_value))
|
||||||
|
} else {
|
||||||
|
let result = self.set(new_value);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filled(&self) -> bool {
|
||||||
|
self.get().is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> OnceExt for std::cell::OnceCell<T> {
|
||||||
|
type T = T;
|
||||||
|
|
||||||
|
fn try_borrow_with<F, E>(&self, f: F) -> Result<&T, E>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Result<T, E>,
|
||||||
|
{
|
||||||
|
if let Some(value) = self.get() {
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not how the unstable `OnceLock::get_or_try_init` works. That only starts `f` if
|
||||||
|
// no other `f` is executing and the value is not initialized. However, correctly implementing that is
|
||||||
|
// hard (one has properly handle panics in `f`) and not doable with the stable API of `OnceLock`.
|
||||||
|
let value = f()?;
|
||||||
|
// Another thread might have initialized `self` since we checked that `self.get()` returns `None`. If this is the case, `self.set()`
|
||||||
|
// returns an error. We ignore it and return the value set by the other
|
||||||
|
// thread.
|
||||||
|
let _ = self.set(value);
|
||||||
|
Ok(self.get().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace(&mut self, new_value: T) -> Option<T> {
|
||||||
|
if let Some(value) = self.get_mut() {
|
||||||
|
Some(std::mem::replace(value, new_value))
|
||||||
|
} else {
|
||||||
|
let result = self.set(new_value);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filled(&self) -> bool {
|
||||||
|
self.get().is_some()
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user