rust-lang / rust-lang/libs-team
ACP For `OnceLock::get_unchecked` and `LazyLock::get_unchecked`
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 178
- Forks
- 28
- Avg merge
- 15m
- Merged PRs (30d)
- 1
Description
Proposal
Problem statement
Currently there is no way to get a reference to the value in a OnceLock or LazyLock without there being an atomic initialization check on every access, even if you know it has already been initialized, which adds slight overhead to every access.
Motivating examples or use cases
This is one use case where I wanted this:
use derive_more::derive::{Debug, Display};
use lasso::{Spur, ThreadedRodeo};
use rustc_hash::FxBuildHasher;
use std::sync::OnceLock;
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[display("{}", self.as_str())]
#[debug("{:?}", self.as_str())]
pub struct InternedStr(Spur);
impl InternedStr {
pub fn intern(s: &str) -> Self {
InternedStr(
INTERNER
.get_or_init(|| ThreadedRodeo::with_hasher(FxBuildHasher))
.get_or_intern(s),
)
}
pub fn as_str(self) -> &'static str {
// SAFETY: if `self` has been constructed, then `INTERNER` has already been initialized by `Self::intern`
// even though this uses `unwrap_unchecked`, the compiler still needs to atomically load the
// initialization flag inside of `get` because the atomic ordering could matter, but it does not here
let interner = unsafe { INTERNER.get().unwrap_unchecked() };
// SAFETY: if `self` has been constructed, then `self.0` was retrieved from `INTERNER` so it will be resolved
unsafe { interner.try_resolve(&self.0).unwrap_unchecked() }
}
}
static INTERNER: OnceLock<ThreadedRodeo<Spur, FxBuildHasher>> = OnceLock::new();
Solution sketch
The solution would be having OnceLock::get_unchecked/LazyLock::get_unchecked so that the atomic initialization flag doesnt have to be read at all.
They would have these signatures:
impl<T, F> LazyLock<T, F> {
pub unsafe fn get_unchecked(this: &Self) -> &T;
pub unsafe fn get_unchecked_mut(this: &mut Self) -> &mut T;
}
impl<T> OnceLock<T> {
pub unsafe fn get_unchecked(&self) -> &T;
pub unsafe fn get_unchecked_mut(&mut self) -> &mut T;
}
Alternatives
There are no other alternatives.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the proposed OnceLock::get_unchecked and LazyLock::get_unchecked APIs and the motivating InternedStr example. Assess the safety contracts and whether the proposed immutable and mutable methods meet the stated goal; done means reaching and documenting an ACP decision on the API design.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100