Simplify lifetime of environment::principal()

It's clearer that using it with `Rc::from_raw()` is safe since we don't have to
go through an `Arc<T>`.
This commit is contained in:
Mahmoud Al-Qudsi 2024-05-16 20:46:28 -05:00
parent ec1bf60941
commit 4ce13f0adb
2 changed files with 12 additions and 17 deletions

View File

@ -188,7 +188,7 @@ impl EnvStack {
/// Return whether we are the principal stack. /// Return whether we are the principal stack.
pub fn is_principal(&self) -> bool { pub fn is_principal(&self) -> bool {
std::ptr::eq(self, &**Self::principal()) std::ptr::eq(self, Self::principal())
} }
/// Helpers to get and set the proc statuses. /// Helpers to get and set the proc statuses.
@ -367,10 +367,10 @@ impl EnvStack {
} }
/// Access the principal variable stack, associated with the principal parser. /// Access the principal variable stack, associated with the principal parser.
pub fn principal() -> &'static Arc<EnvStack> { pub fn principal() -> &'static EnvStack {
use std::sync::OnceLock; use std::sync::OnceLock;
static PRINCIPAL_STACK: OnceLock<Arc<EnvStack>> = OnceLock::new(); static PRINCIPAL_STACK: OnceLock<EnvStack> = OnceLock::new();
&PRINCIPAL_STACK.get_or_init(|| Arc::new(EnvStack::new())) &PRINCIPAL_STACK.get_or_init(|| EnvStack::new())
} }
pub fn set_argv(&self, argv: Vec<WString>) { pub fn set_argv(&self, argv: Vec<WString>) {
@ -554,7 +554,7 @@ fn setup_path() {
pub static INHERITED_VARS: OnceCell<HashMap<WString, WString>> = OnceCell::new(); pub static INHERITED_VARS: OnceCell<HashMap<WString, WString>> = OnceCell::new();
pub fn env_init(paths: Option<&ConfigPaths>, do_uvars: bool, default_paths: bool) { pub fn env_init(paths: Option<&ConfigPaths>, do_uvars: bool, default_paths: bool) {
let vars = &**EnvStack::principal(); let vars = EnvStack::principal();
let env_iter: Vec<_> = std::env::vars_os() let env_iter: Vec<_> = std::env::vars_os()
.map(|(k, v)| (str2wcstring(k.as_bytes()), str2wcstring(v.as_bytes()))) .map(|(k, v)| (str2wcstring(k.as_bytes()), str2wcstring(v.as_bytes())))

View File

@ -402,18 +402,13 @@ impl Parser {
pub fn principal_parser() -> &'static Parser { pub fn principal_parser() -> &'static Parser {
use std::cell::OnceCell; use std::cell::OnceCell;
static PRINCIPAL: MainThread<OnceCell<ParserRef>> = MainThread::new(OnceCell::new()); static PRINCIPAL: MainThread<OnceCell<ParserRef>> = MainThread::new(OnceCell::new());
&PRINCIPAL &PRINCIPAL.get().get_or_init(|| {
.get() // Safety: EnvStack::principal() returns a `static` variable guaranteed to always be
// The parser is !Send/!Sync and strictly single-threaded, but we can have // alive. We just don't want to hard-code the lifetime in `Parser` so we wrap the
// multi-threaded access to its variables stack (why, though?) so EnvStack::principal() // `EnvStack` in an `Rc` before sending it along.
// returns an Arc<EnvStack> instead of an Rc<EnvStack>. Since the Arc<EnvStack> is let env_rc = unsafe { Rc::from_raw(EnvStack::principal() as *const _) };
// statically allocated and always valid (not even destroyed on exit), we can safely Parser::new(env_rc, true)
// transform the Arc<T> into an Rc<T> and save Parser from needing atomic ref counting })
// to manage its further references.
.get_or_init(|| {
let env_rc = unsafe { Rc::from_raw(&**EnvStack::principal() as *const _) };
Parser::new(env_rc, true)
})
} }
/// Assert that this parser is allowed to execute on the current thread. /// Assert that this parser is allowed to execute on the current thread.