-
Notifications
You must be signed in to change notification settings - Fork 23
Open
Labels
ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)API Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard librariesA proposal to add or alter unstable APIs in the standard libraries
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.
joboet
Metadata
Metadata
Assignees
Labels
ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)API Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard librariesA proposal to add or alter unstable APIs in the standard libraries