Unify owned Env types between platforms

Also, update the same pattern of reuse in `sys::args` to match.
This commit is contained in:
Thalia Archibald 2025-04-21 22:24:02 -07:00
parent 4695212566
commit 01485c9fe9
15 changed files with 98 additions and 348 deletions

View file

@ -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"))),

View file

@ -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()]);

View file

@ -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) }

View file

@ -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()))

View file

@ -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::*;
@ -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.

View file

@ -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![]);

48
library/std/src/sys/env/common.rs vendored Normal file
View file

@ -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()
}
}

View file

@ -1,10 +1,11 @@
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;
use crate::{fmt, io, vec};
static ENV: Mutex<Option<HashMap<OsString, OsString>>> = Mutex::new(None);
@ -44,60 +45,15 @@ pub fn init(env: *const *const c_char) {
}
}
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 {
let Self { slice } = self;
f.debug_list()
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
.finish()
}
}
impl Env {
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
let Self { iter } = self;
EnvStrDebug { slice: iter.as_slice() }
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { iter } = self;
f.debug_list().entries(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()
}
}
/// 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::<Vec<_>>();
let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect();
Env { iter: result.into_iter() }
Env::new(result)
}
pub fn getenv(k: &OsStr) -> Option<OsString> {

View file

@ -2,6 +2,17 @@
#![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;

View file

@ -1,10 +1,11 @@
#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers
pub use super::common::Env;
use crate::collections::HashMap;
use crate::ffi::{OsStr, OsString};
use crate::io;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::{Mutex, Once};
use crate::{fmt, io, vec};
// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
#[cfg_attr(test, linkage = "available_externally")]
@ -27,61 +28,13 @@ fn create_env_store() -> &'static EnvStore {
unsafe { &*(ENV.load(Ordering::Relaxed) as *const EnvStore) }
}
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 {
let Self { slice } = self;
f.debug_list()
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
.finish()
}
}
impl Env {
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
let Self { iter } = self;
EnvStrDebug { slice: iter.as_slice() }
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { iter } = self;
f.debug_list().entries(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()
}
}
pub fn env() -> Env {
let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> {
map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
};
let iter = get_env_store()
.map(|env| clone_to_vec(&env.lock().unwrap()))
.unwrap_or_default()
.into_iter();
Env { iter }
let env = get_env_store().map(|env| clone_to_vec(&env.lock().unwrap())).unwrap_or_default();
Env::new(env)
}
pub fn getenv(k: &OsStr) -> Option<OsString> {

View file

@ -1,11 +1,12 @@
use core::slice::memchr;
pub use super::common::Env;
use crate::ffi::{CStr, OsStr, OsString};
use crate::io;
use crate::os::raw::{c_char, c_int};
use crate::os::solid::ffi::{OsStrExt, OsStringExt};
use crate::sync::{PoisonError, RwLock};
use crate::sys::common::small_c_string::run_with_cstr;
use crate::{fmt, io, vec};
static ENV_LOCK: RwLock<()> = RwLock::new(());
@ -13,51 +14,6 @@ pub fn env_read_lock() -> impl Drop {
ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner)
}
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 {
let Self { slice } = self;
f.debug_list()
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
.finish()
}
}
impl Env {
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
let Self { iter } = self;
EnvStrDebug { slice: iter.as_slice() }
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { iter } = self;
f.debug_list().entries(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()
}
}
/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
@ -76,7 +32,7 @@ pub fn env() -> Env {
environ = environ.add(1);
}
}
return Env { iter: result.into_iter() };
return Env::new(result);
}
fn parse(input: &[u8]) -> Option<(OsString, OsString)> {

View file

@ -1,46 +1,10 @@
pub use super::common::Env;
use crate::ffi::{OsStr, OsString};
use crate::{fmt, io};
pub struct EnvStrDebug<'a> {
iter: &'a [(OsString, OsString)],
}
impl fmt::Debug for EnvStrDebug<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
for (a, b) in self.iter {
list.entry(&(a.to_str().unwrap(), b.to_str().unwrap()));
}
list.finish()
}
}
pub struct Env(crate::vec::IntoIter<(OsString, OsString)>);
impl Env {
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
EnvStrDebug { iter: self.0.as_slice() }
}
}
impl Iterator for Env {
type Item = (OsString, OsString);
fn next(&mut self) -> Option<(OsString, OsString)> {
self.0.next()
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
use crate::io;
pub fn env() -> Env {
let env = uefi_env::get_all().expect("not supported on this platform");
Env(env.into_iter())
Env::new(env)
}
pub fn getenv(key: &OsStr) -> Option<OsString> {

View file

@ -2,57 +2,13 @@ use core::slice::memchr;
use libc::c_char;
pub use super::common::Env;
use crate::ffi::{CStr, OsStr, OsString};
use crate::io;
use crate::os::unix::prelude::*;
use crate::sync::{PoisonError, RwLock};
use crate::sys::common::small_c_string::run_with_cstr;
use crate::sys::cvt;
use crate::{fmt, io, 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 {
let Self { slice } = self;
f.debug_list()
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
.finish()
}
}
impl Env {
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
let Self { iter } = self;
EnvStrDebug { slice: iter.as_slice() }
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { iter } = self;
f.debug_list().entries(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()
}
}
// Use `_NSGetEnviron` on Apple platforms.
//
@ -112,7 +68,7 @@ pub fn env() -> Env {
environ = environ.add(1);
}
}
return Env { iter: result.into_iter() };
return Env::new(result);
}
fn parse(input: &[u8]) -> Option<(OsString, OsString)> {

View file

@ -1,55 +1,11 @@
use core::slice::memchr;
pub use super::common::Env;
use crate::ffi::{CStr, OsStr, OsString};
use crate::io;
use crate::os::wasi::prelude::*;
use crate::sys::common::small_c_string::run_with_cstr;
use crate::sys::pal::os::{cvt, libc};
use crate::{fmt, io, 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 {
let Self { slice } = self;
f.debug_list()
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
.finish()
}
}
impl Env {
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
let Self { iter } = self;
EnvStrDebug { slice: iter.as_slice() }
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { iter } = self;
f.debug_list().entries(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()
}
}
cfg_if::cfg_if! {
if #[cfg(target_feature = "atomics")] {
@ -91,7 +47,7 @@ pub fn env() -> Env {
environ = environ.add(1);
}
}
return Env { iter: result.into_iter() };
return Env::new(result);
}
// See src/libstd/sys/pal/unix/os.rs, same as that

View file

@ -1,9 +1,10 @@
pub use super::common::Env;
use crate::collections::HashMap;
use crate::ffi::{OsStr, OsString};
use crate::io;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::{Mutex, Once};
use crate::sys::pal::os::{get_application_parameters, params};
use crate::{fmt, io, vec};
static ENV: AtomicUsize = AtomicUsize::new(0);
static ENV_INIT: Once = Once::new();
@ -28,59 +29,13 @@ fn get_env_store() -> &'static EnvStore {
unsafe { &*core::ptr::with_exposed_provenance::<EnvStore>(ENV.load(Ordering::Relaxed)) }
}
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 {
let Self { slice } = self;
f.debug_list()
.entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
.finish()
}
}
impl Env {
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
let Self { iter } = self;
EnvStrDebug { slice: iter.as_slice() }
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { iter } = self;
f.debug_list().entries(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()
}
}
pub fn env() -> Env {
let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> {
map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
};
let iter = clone_to_vec(&*get_env_store().lock().unwrap()).into_iter();
Env { iter }
let env = clone_to_vec(&*get_env_store().lock().unwrap());
Env::new(env)
}
pub fn getenv(k: &OsStr) -> Option<OsString> {