Skip to content

Move sys::pal::os::Env into sys::env #140143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions compiler/rustc_data_structures/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,15 @@ impls_dyn_send_neg!(
[std::io::StderrLock<'_>]
);

#[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))]
// Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms
#[cfg(any(
unix,
target_os = "hermit",
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "solid_asp3",
target_os = "wasi",
target_os = "xous"
))]
// Consistent with `std`, `env_imp::Env` is `!Sync` in these platforms
impl !DynSend for std::env::VarsOs {}

macro_rules! already_send {
Expand Down Expand Up @@ -106,8 +113,15 @@ impls_dyn_sync_neg!(
[std::sync::mpsc::Sender<T> where T]
);

#[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))]
// Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms
#[cfg(any(
unix,
target_os = "hermit",
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "solid_asp3",
target_os = "wasi",
target_os = "xous"
))]
// Consistent with `std`, `env_imp::Env` is `!Sync` in these platforms
impl !DynSync for std::env::VarsOs {}

macro_rules! already_sync {
Expand Down
12 changes: 6 additions & 6 deletions library/std/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use crate::error::Error;
use crate::ffi::{OsStr, OsString};
use crate::path::{Path, PathBuf};
use crate::sys::os as os_imp;
use crate::sys::{env as env_imp, os as os_imp};
use crate::{fmt, io, sys};

/// Returns the current working directory as a [`PathBuf`].
Expand Down Expand Up @@ -96,7 +96,7 @@ pub struct Vars {
/// [`env::vars_os()`]: vars_os
#[stable(feature = "env", since = "1.0.0")]
pub struct VarsOs {
inner: os_imp::Env,
inner: env_imp::Env,
}

/// Returns an iterator of (variable, value) pairs of strings, for all the
Expand Down Expand Up @@ -150,7 +150,7 @@ pub fn vars() -> Vars {
#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn vars_os() -> VarsOs {
VarsOs { inner: os_imp::env() }
VarsOs { inner: env_imp::env() }
}

#[stable(feature = "env", since = "1.0.0")]
Expand Down Expand Up @@ -259,7 +259,7 @@ pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
}

fn _var_os(key: &OsStr) -> Option<OsString> {
os_imp::getenv(key)
env_imp::getenv(key)
}

/// The error type for operations interacting with environment variables.
Expand Down Expand Up @@ -363,7 +363,7 @@ impl Error for VarError {
#[stable(feature = "env", since = "1.0.0")]
pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
let (key, value) = (key.as_ref(), value.as_ref());
unsafe { os_imp::setenv(key, value) }.unwrap_or_else(|e| {
unsafe { env_imp::setenv(key, value) }.unwrap_or_else(|e| {
panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}")
})
}
Expand Down Expand Up @@ -434,7 +434,7 @@ pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
#[stable(feature = "env", since = "1.0.0")]
pub unsafe fn remove_var<K: AsRef<OsStr>>(key: K) {
let key = key.as_ref();
unsafe { os_imp::unsetenv(key) }
unsafe { env_imp::unsetenv(key) }
.unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}"))
}

Expand Down
10 changes: 10 additions & 0 deletions library/std/src/sys/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

#![forbid(unsafe_op_in_unsafe_fn)]

#[cfg(any(
all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))),
target_family = "windows",
target_os = "hermit",
target_os = "uefi",
target_os = "wasi",
target_os = "xous",
))]
mod common;

cfg_if::cfg_if! {
if #[cfg(any(
all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))),
Expand Down
5 changes: 1 addition & 4 deletions library/std/src/sys/args/uefi.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
use r_efi::protocols::loaded_image;

pub use super::common::Args;
use crate::env::current_exe;
use crate::ffi::OsString;
use crate::iter::Iterator;
use crate::sys::pal::helpers;

#[path = "common.rs"]
mod common;
pub use common::Args;

pub fn args() -> Args {
let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]);

Expand Down
5 changes: 1 addition & 4 deletions library/std/src/sys/args/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@

#![allow(dead_code)] // runtime init functions not used during testing

pub use super::common::Args;
use crate::ffi::CStr;
#[cfg(target_os = "hermit")]
use crate::os::hermit::ffi::OsStringExt;
#[cfg(not(target_os = "hermit"))]
use crate::os::unix::ffi::OsStringExt;

#[path = "common.rs"]
mod common;
pub use common::Args;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) {
unsafe { imp::init(argc, argv) }
Expand Down
5 changes: 1 addition & 4 deletions library/std/src/sys/args/wasi.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
#![forbid(unsafe_op_in_unsafe_fn)]

pub use super::common::Args;
use crate::ffi::{CStr, OsStr, OsString};
use crate::os::wasi::ffi::OsStrExt;

#[path = "common.rs"]
mod common;
pub use common::Args;

/// Returns the command line arguments
pub fn args() -> Args {
Args::new(maybe_args().unwrap_or(Vec::new()))
Expand Down
5 changes: 1 addition & 4 deletions library/std/src/sys/args/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#[cfg(test)]
mod tests;

pub use super::common::Args;
use crate::ffi::{OsStr, OsString};
use crate::num::NonZero;
use crate::os::windows::prelude::*;
Expand All @@ -18,10 +19,6 @@ use crate::sys_common::AsInner;
use crate::sys_common::wstr::WStrUnits;
use crate::{io, iter, ptr};

#[path = "common.rs"]
mod common;
pub use common::Args;

pub fn args() -> Args {
// SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16
// string so it's safe for `WStrUnits` to use.
Expand Down
5 changes: 1 addition & 4 deletions library/std/src/sys/args/xous.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
pub use super::common::Args;
use crate::sys::pal::os::get_application_parameters;
use crate::sys::pal::os::params::ArgumentList;

#[path = "common.rs"]
mod common;
pub use common::Args;

pub fn args() -> Args {
let Some(params) = get_application_parameters() else {
return Args::new(vec![]);
Expand Down
48 changes: 48 additions & 0 deletions library/std/src/sys/env/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::ffi::OsString;
use crate::{fmt, vec};

pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
}

// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
pub struct EnvStrDebug<'a> {
slice: &'a [(OsString, OsString)],
}

impl fmt::Debug for EnvStrDebug<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list()
.entries(self.slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
.finish()
}
}

impl Env {
pub(super) fn new(env: Vec<(OsString, OsString)>) -> Self {
Env { iter: env.into_iter() }
}

pub fn str_debug(&self) -> impl fmt::Debug + '_ {
EnvStrDebug { slice: self.iter.as_slice() }
}
}

impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter.as_slice()).finish()
}
}

impl !Send for Env {}
impl !Sync for Env {}

impl Iterator for Env {
type Item = (OsString, OsString);
fn next(&mut self) -> Option<(OsString, OsString)> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
72 changes: 72 additions & 0 deletions library/std/src/sys/env/hermit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use core::slice::memchr;

pub use super::common::Env;
use crate::collections::HashMap;
use crate::ffi::{CStr, OsStr, OsString, c_char};
use crate::io;
use crate::os::hermit::ffi::OsStringExt;
use crate::sync::Mutex;

static ENV: Mutex<Option<HashMap<OsString, OsString>>> = Mutex::new(None);

pub fn init(env: *const *const c_char) {
let mut guard = ENV.lock().unwrap();
let map = guard.insert(HashMap::new());

if env.is_null() {
return;
}

unsafe {
let mut environ = env;
while !(*environ).is_null() {
if let Some((key, value)) = parse(CStr::from_ptr(*environ).to_bytes()) {
map.insert(key, value);
}
environ = environ.add(1);
}
}

fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
// Strategy (copied from glibc): Variable name and value are separated
// by an ASCII equals sign '='. Since a variable name must not be
// empty, allow variable names starting with an equals sign. Skip all
// malformed lines.
if input.is_empty() {
return None;
}
let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
pos.map(|p| {
(
OsStringExt::from_vec(input[..p].to_vec()),
OsStringExt::from_vec(input[p + 1..].to_vec()),
)
})
}
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
let guard = ENV.lock().unwrap();
let env = guard.as_ref().unwrap();

let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect();

Env::new(result)
}

pub fn getenv(k: &OsStr) -> Option<OsString> {
ENV.lock().unwrap().as_ref().unwrap().get(k).cloned()
}

pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
let (k, v) = (k.to_owned(), v.to_owned());
ENV.lock().unwrap().as_mut().unwrap().insert(k, v);
Ok(())
}

pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> {
ENV.lock().unwrap().as_mut().unwrap().remove(k);
Ok(())
}
48 changes: 48 additions & 0 deletions library/std/src/sys/env/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! Platform-dependent environment variables abstraction.

#![forbid(unsafe_op_in_unsafe_fn)]

#[cfg(any(
target_family = "unix",
target_os = "hermit",
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "solid_asp3",
target_os = "uefi",
target_os = "wasi",
target_os = "xous",
))]
mod common;

cfg_if::cfg_if! {
if #[cfg(target_family = "unix")] {
mod unix;
pub use unix::*;
} else if #[cfg(target_family = "windows")] {
mod windows;
pub use windows::*;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use hermit::*;
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use sgx::*;
} else if #[cfg(target_os = "solid_asp3")] {
mod solid;
pub use solid::*;
} else if #[cfg(target_os = "uefi")] {
mod uefi;
pub use uefi::*;
} else if #[cfg(target_os = "wasi")] {
mod wasi;
pub use wasi::*;
} else if #[cfg(target_os = "xous")] {
mod xous;
pub use xous::*;
} else if #[cfg(target_os = "zkvm")] {
mod zkvm;
pub use zkvm::*;
} else {
mod unsupported;
pub use unsupported::*;
}
}
Loading
Loading