Skip to content

Commit 77f0841

Browse files
authored
refactor: Remove lazycell (#16224)
### What does this PR try to resolve? Fixes #9310 ### How to test and review this PR?
2 parents a8e5bf3 + 41c97aa commit 77f0841

File tree

8 files changed

+71
-34
lines changed

8 files changed

+71
-34
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ indexmap = "2.12.0"
6363
itertools = "0.14.0"
6464
jiff = { version = "0.2.15", default-features = false, features = [ "std" ] }
6565
jobserver = "0.1.34"
66-
lazycell = "1.3.0"
6766
libc = "0.2.177"
6867
libgit2-sys = "0.18.2"
6968
libloading = "0.8.9"
@@ -185,7 +184,6 @@ indexmap.workspace = true
185184
itertools.workspace = true
186185
jiff = { workspace = true, features = ["serde", "std"] }
187186
jobserver.workspace = true
188-
lazycell.workspace = true
189187
libgit2-sys.workspace = true
190188
memchr.workspace = true
191189
opener.workspace = true

src/cargo/core/compiler/build_runner/compilation_files.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
//! See [`CompilationFiles`].
22
3+
use std::cell::OnceCell;
34
use std::collections::HashMap;
45
use std::fmt;
56
use std::hash::{Hash, Hasher};
67
use std::path::{Path, PathBuf};
78
use std::sync::Arc;
89

9-
use lazycell::LazyCell;
1010
use tracing::debug;
1111

1212
use super::{BuildContext, BuildRunner, CompileKind, FileFlavor, Layout};
1313
use crate::core::compiler::{CompileMode, CompileTarget, CrateType, FileType, Unit};
1414
use crate::core::{Target, TargetKind, Workspace};
15-
use crate::util::{self, CargoResult, StableHasher};
15+
use crate::util::{self, CargoResult, OnceExt, StableHasher};
1616

1717
/// This is a generic version number that can be changed to make
1818
/// backwards-incompatible changes to any file structures in the output
@@ -128,7 +128,7 @@ pub struct CompilationFiles<'a, 'gctx> {
128128
/// Metadata hash to use for each unit.
129129
metas: HashMap<Unit, Metadata>,
130130
/// For each Unit, a list all files produced.
131-
outputs: HashMap<Unit, LazyCell<Arc<Vec<OutputFile>>>>,
131+
outputs: HashMap<Unit, OnceCell<Arc<Vec<OutputFile>>>>,
132132
}
133133

134134
/// Info about a single file emitted by the compiler.
@@ -168,7 +168,7 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
168168
let outputs = metas
169169
.keys()
170170
.cloned()
171-
.map(|unit| (unit, LazyCell::new()))
171+
.map(|unit| (unit, OnceCell::new()))
172172
.collect();
173173
CompilationFiles {
174174
ws: build_runner.bcx.ws,

src/cargo/core/compiler/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub mod unit_dependencies;
5252
pub mod unit_graph;
5353

5454
use std::borrow::Cow;
55+
use std::cell::OnceCell;
5556
use std::collections::{BTreeMap, HashMap, HashSet};
5657
use std::env;
5758
use std::ffi::{OsStr, OsString};
@@ -66,7 +67,6 @@ use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
6667
use anyhow::{Context as _, Error};
6768
use cargo_platform::{Cfg, Platform};
6869
use itertools::Itertools;
69-
use lazycell::LazyCell;
7070
use regex::Regex;
7171
use tracing::{debug, instrument, trace};
7272

@@ -95,6 +95,7 @@ pub use crate::core::compiler::unit::{Unit, UnitInterner};
9595
use crate::core::manifest::TargetSourcePath;
9696
use crate::core::profiles::{PanicStrategy, Profile, StripInner};
9797
use crate::core::{Feature, PackageId, Target, Verbosity};
98+
use crate::util::OnceExt;
9899
use crate::util::context::WarningHandling;
99100
use crate::util::errors::{CargoResult, VerboseError};
100101
use crate::util::interning::InternedString;
@@ -1897,7 +1898,7 @@ struct OutputOptions {
18971898
/// is fresh. The file is created lazily so that in the normal case, lots
18981899
/// of empty files are not created. If this is None, the output will not
18991900
/// be cached (such as when replaying cached messages).
1900-
cache_cell: Option<(PathBuf, LazyCell<File>)>,
1901+
cache_cell: Option<(PathBuf, OnceCell<File>)>,
19011902
/// If `true`, display any diagnostics.
19021903
/// Other types of JSON messages are processed regardless
19031904
/// of the value of this flag.
@@ -1917,7 +1918,7 @@ impl OutputOptions {
19171918
let path = build_runner.files().message_cache_path(unit);
19181919
// Remove old cache, ignore ENOENT, which is the common case.
19191920
drop(fs::remove_file(&path));
1920-
let cache_cell = Some((path, LazyCell::new()));
1921+
let cache_cell = Some((path, OnceCell::new()));
19211922
let show_diagnostics =
19221923
build_runner.bcx.gctx.warning_handling().unwrap_or_default() != WarningHandling::Allow;
19231924
OutputOptions {

src/cargo/core/package.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::cell::OnceCell;
12
use std::cell::{Cell, Ref, RefCell, RefMut};
23
use std::cmp::Ordering;
34
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
@@ -12,7 +13,6 @@ use anyhow::Context as _;
1213
use cargo_util_schemas::manifest::{Hints, RustVersion};
1314
use curl::easy::Easy;
1415
use curl::multi::{EasyHandle, Multi};
15-
use lazycell::LazyCell;
1616
use semver::Version;
1717
use serde::Serialize;
1818
use tracing::debug;
@@ -287,7 +287,7 @@ impl hash::Hash for Package {
287287
/// This is primarily used to convert a set of `PackageId`s to `Package`s. It
288288
/// will download as needed, or used the cached download if available.
289289
pub struct PackageSet<'gctx> {
290-
packages: HashMap<PackageId, LazyCell<Package>>,
290+
packages: HashMap<PackageId, OnceCell<Package>>,
291291
sources: RefCell<SourceMap<'gctx>>,
292292
gctx: &'gctx GlobalContext,
293293
multi: Multi,
@@ -408,7 +408,7 @@ impl<'gctx> PackageSet<'gctx> {
408408
Ok(PackageSet {
409409
packages: package_ids
410410
.iter()
411-
.map(|&id| (id, LazyCell::new()))
411+
.map(|&id| (id, OnceCell::new()))
412412
.collect(),
413413
sources: RefCell::new(sources),
414414
gctx,
@@ -423,7 +423,7 @@ impl<'gctx> PackageSet<'gctx> {
423423
}
424424

425425
pub fn packages(&self) -> impl Iterator<Item = &Package> {
426-
self.packages.values().filter_map(|p| p.borrow())
426+
self.packages.values().filter_map(|p| p.get())
427427
}
428428

429429
pub fn enable_download<'a>(&'a self) -> CargoResult<Downloads<'a, 'gctx>> {
@@ -457,7 +457,7 @@ impl<'gctx> PackageSet<'gctx> {
457457
}
458458

459459
pub fn get_one(&self, id: PackageId) -> CargoResult<&Package> {
460-
if let Some(pkg) = self.packages.get(&id).and_then(|slot| slot.borrow()) {
460+
if let Some(pkg) = self.packages.get(&id).and_then(|slot| slot.get()) {
461461
return Ok(pkg);
462462
}
463463
Ok(self.get_many(Some(id))?.remove(0))
@@ -700,7 +700,7 @@ impl<'a, 'gctx> Downloads<'a, 'gctx> {
700700
.packages
701701
.get(&id)
702702
.ok_or_else(|| internal(format!("couldn't find `{}` in package set", id)))?;
703-
if let Some(pkg) = slot.borrow() {
703+
if let Some(pkg) = slot.get() {
704704
return Ok(Some(pkg));
705705
}
706706

@@ -717,8 +717,8 @@ impl<'a, 'gctx> Downloads<'a, 'gctx> {
717717
let (url, descriptor, authorization) = match pkg {
718718
MaybePackage::Ready(pkg) => {
719719
debug!("{} doesn't need a download", id);
720-
assert!(slot.fill(pkg).is_ok());
721-
return Ok(Some(slot.borrow().unwrap()));
720+
assert!(slot.set(pkg).is_ok());
721+
return Ok(Some(slot.get().unwrap()));
722722
}
723723
MaybePackage::Download {
724724
url,
@@ -941,8 +941,8 @@ impl<'a, 'gctx> Downloads<'a, 'gctx> {
941941
.set(self.next_speed_check.get() + finish_dur);
942942

943943
let slot = &self.set.packages[&dl.id];
944-
assert!(slot.fill(pkg).is_ok());
945-
Ok(slot.borrow().unwrap())
944+
assert!(slot.set(pkg).is_ok());
945+
Ok(slot.get().unwrap())
946946
}
947947

948948
fn enqueue(&mut self, dl: Download<'gctx>, handle: Easy) -> CargoResult<()> {

src/cargo/sources/registry/remote.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ use crate::sources::registry::{LoadResponse, RegistryConfig, RegistryData};
1111
use crate::util::cache_lock::CacheLockMode;
1212
use crate::util::errors::CargoResult;
1313
use crate::util::interning::InternedString;
14-
use crate::util::{Filesystem, GlobalContext};
14+
use crate::util::{Filesystem, GlobalContext, OnceExt};
1515
use anyhow::Context as _;
1616
use cargo_util::paths;
17-
use lazycell::LazyCell;
17+
use std::cell::OnceCell;
1818
use std::cell::{Cell, Ref, RefCell};
1919
use std::fs::File;
2020
use std::mem;
@@ -71,7 +71,7 @@ pub struct RemoteRegistry<'gctx> {
7171
/// [tree object]: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects#_tree_objects
7272
tree: RefCell<Option<git2::Tree<'static>>>,
7373
/// A Git repository that contains the actual index we want.
74-
repo: LazyCell<git2::Repository>,
74+
repo: OnceCell<git2::Repository>,
7575
/// The current HEAD commit of the underlying Git repository.
7676
head: Cell<Option<git2::Oid>>,
7777
/// This stores sha value of the current HEAD commit for convenience.
@@ -103,7 +103,7 @@ impl<'gctx> RemoteRegistry<'gctx> {
103103
gctx,
104104
index_git_ref: GitReference::DefaultBranch,
105105
tree: RefCell::new(None),
106-
repo: LazyCell::new(),
106+
repo: OnceCell::new(),
107107
head: Cell::new(None),
108108
current_sha: Cell::new(None),
109109
needs_update: false,
@@ -378,7 +378,7 @@ impl<'gctx> RegistryData for RemoteRegistry<'gctx> {
378378
// Fetch the latest version of our `index_git_ref` into the index
379379
// checkout.
380380
let url = self.source_id.url();
381-
let repo = self.repo.borrow_mut().unwrap();
381+
let repo = self.repo.get_mut().unwrap();
382382
git::fetch(
383383
repo,
384384
url.as_str(),

src/cargo/util/once.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ pub trait OnceExt {
1010
where
1111
F: FnOnce() -> Result<Self::T, E>;
1212

13+
/// This might run `f` multiple times if different threads start initializing at once.
14+
fn try_borrow_mut_with<F, E>(&mut self, f: F) -> Result<&mut Self::T, E>
15+
where
16+
F: FnOnce() -> Result<Self::T, E>;
17+
1318
fn replace(&mut self, new_value: Self::T) -> Option<Self::T>;
1419

1520
fn filled(&self) -> bool;
@@ -37,6 +42,25 @@ impl<T> OnceExt for std::sync::OnceLock<T> {
3742
Ok(self.get().unwrap())
3843
}
3944

45+
fn try_borrow_mut_with<F, E>(&mut self, f: F) -> Result<&mut T, E>
46+
where
47+
F: FnOnce() -> Result<T, E>,
48+
{
49+
let value = if let Some(value) = self.take() {
50+
value
51+
} else {
52+
// This is not how the unstable `OnceLock::get_or_try_init` works. That only starts `f` if
53+
// no other `f` is executing and the value is not initialized. However, correctly implementing that is
54+
// hard (one has properly handle panics in `f`) and not doable with the stable API of `OnceLock`.
55+
f()?
56+
};
57+
// Another thread might have initialized `self` since we checked that `self.get()` returns `None`. If this is the case, `self.set()`
58+
// returns an error. We ignore it and return the value set by the other
59+
// thread.
60+
let _ = self.set(value);
61+
Ok(self.get_mut().unwrap())
62+
}
63+
4064
fn replace(&mut self, new_value: T) -> Option<T> {
4165
if let Some(value) = self.get_mut() {
4266
Some(std::mem::replace(value, new_value))
@@ -74,6 +98,25 @@ impl<T> OnceExt for std::cell::OnceCell<T> {
7498
Ok(self.get().unwrap())
7599
}
76100

101+
fn try_borrow_mut_with<F, E>(&mut self, f: F) -> Result<&mut T, E>
102+
where
103+
F: FnOnce() -> Result<T, E>,
104+
{
105+
let value = if let Some(value) = self.take() {
106+
value
107+
} else {
108+
// This is not how the unstable `OnceLock::get_or_try_init` works. That only starts `f` if
109+
// no other `f` is executing and the value is not initialized. However, correctly implementing that is
110+
// hard (one has properly handle panics in `f`) and not doable with the stable API of `OnceLock`.
111+
f()?
112+
};
113+
// Another thread might have initialized `self` since we checked that `self.get()` returns `None`. If this is the case, `self.set()`
114+
// returns an error. We ignore it and return the value set by the other
115+
// thread.
116+
let _ = self.set(value);
117+
Ok(self.get_mut().unwrap())
118+
}
119+
77120
fn replace(&mut self, new_value: T) -> Option<T> {
78121
if let Some(value) = self.get_mut() {
79122
Some(std::mem::replace(value, new_value))

src/cargo/util/toml/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use annotate_snippets::{AnnotationKind, Group, Level, Snippet};
22
use std::borrow::Cow;
3+
use std::cell::OnceCell;
34
use std::collections::{BTreeMap, BTreeSet, HashMap};
45
use std::ffi::OsStr;
56
use std::path::{Path, PathBuf};
@@ -17,7 +18,6 @@ use cargo_util_schemas::manifest::{
1718
};
1819
use cargo_util_schemas::manifest::{RustVersion, StringOrBool};
1920
use itertools::Itertools;
20-
use lazycell::LazyCell;
2121
use pathdiff::diff_paths;
2222
use url::Url;
2323

@@ -33,7 +33,9 @@ use crate::sources::{CRATES_IO_INDEX, CRATES_IO_REGISTRY};
3333
use crate::util::errors::{CargoResult, ManifestError};
3434
use crate::util::interning::InternedString;
3535
use crate::util::lints::{get_key_value_span, rel_cwd_manifest_path};
36-
use crate::util::{self, GlobalContext, IntoUrl, OptVersionReq, context::ConfigRelativePath};
36+
use crate::util::{
37+
self, GlobalContext, IntoUrl, OnceExt, OptVersionReq, context::ConfigRelativePath,
38+
};
3739

3840
mod embedded;
3941
mod targets;
@@ -299,7 +301,7 @@ fn normalize_toml(
299301
) -> CargoResult<manifest::TomlManifest> {
300302
let package_root = manifest_file.parent().unwrap();
301303

302-
let inherit_cell: LazyCell<InheritableFields> = LazyCell::new();
304+
let inherit_cell: OnceCell<InheritableFields> = OnceCell::new();
303305
let inherit = || {
304306
inherit_cell
305307
.try_borrow_with(|| load_inheritable_fields(gctx, manifest_file, &workspace_config))

0 commit comments

Comments
 (0)