about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThalia Archibald <thalia@archibald.dev>2025-04-21 22:24:02 -0700
committerThalia Archibald <thalia@archibald.dev>2025-04-21 22:38:22 -0700
commit01485c9fe9a50b48fd4c78e7116dcaa2aeb87a40 (patch)
treeadcfc1020244397b7260945f2b6c78bf55f7f8b3
parent46952125661fa7bb6a016a6be4e03620da16a077 (diff)
downloadrust-01485c9fe9a50b48fd4c78e7116dcaa2aeb87a40.tar.gz
rust-01485c9fe9a50b48fd4c78e7116dcaa2aeb87a40.zip
Unify owned `Env` types between platforms
Also, update the same pattern of reuse in `sys::args` to match.
-rw-r--r--library/std/src/sys/args/mod.rs10
-rw-r--r--library/std/src/sys/args/uefi.rs5
-rw-r--r--library/std/src/sys/args/unix.rs5
-rw-r--r--library/std/src/sys/args/wasi.rs5
-rw-r--r--library/std/src/sys/args/windows.rs5
-rw-r--r--library/std/src/sys/args/xous.rs5
-rw-r--r--library/std/src/sys/env/common.rs48
-rw-r--r--library/std/src/sys/env/hermit.rs52
-rw-r--r--library/std/src/sys/env/mod.rs11
-rw-r--r--library/std/src/sys/env/sgx.rs55
-rw-r--r--library/std/src/sys/env/solid.rs50
-rw-r--r--library/std/src/sys/env/uefi.rs42
-rw-r--r--library/std/src/sys/env/unix.rs50
-rw-r--r--library/std/src/sys/env/wasi.rs50
-rw-r--r--library/std/src/sys/env/xous.rs53
15 files changed, 98 insertions, 348 deletions
diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs
index 6a37b32d229..0011f55dc14 100644
--- a/library/std/src/sys/args/mod.rs
+++ b/library/std/src/sys/args/mod.rs
@@ -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"))),
diff --git a/library/std/src/sys/args/uefi.rs b/library/std/src/sys/args/uefi.rs
index 84406c7f69d..02dada382ef 100644
--- a/library/std/src/sys/args/uefi.rs
+++ b/library/std/src/sys/args/uefi.rs
@@ -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()]);
 
diff --git a/library/std/src/sys/args/unix.rs b/library/std/src/sys/args/unix.rs
index c087fd62965..a7b79ad396e 100644
--- a/library/std/src/sys/args/unix.rs
+++ b/library/std/src/sys/args/unix.rs
@@ -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) }
diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasi.rs
index 4795789e4c7..72063a87dc9 100644
--- a/library/std/src/sys/args/wasi.rs
+++ b/library/std/src/sys/args/wasi.rs
@@ -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()))
diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs
index 47f0e5f2d05..81c44fabdcc 100644
--- a/library/std/src/sys/args/windows.rs
+++ b/library/std/src/sys/args/windows.rs
@@ -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.
diff --git a/library/std/src/sys/args/xous.rs b/library/std/src/sys/args/xous.rs
index 09a47283d65..2010bad14d1 100644
--- a/library/std/src/sys/args/xous.rs
+++ b/library/std/src/sys/args/xous.rs
@@ -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![]);
diff --git a/library/std/src/sys/env/common.rs b/library/std/src/sys/env/common.rs
new file mode 100644
index 00000000000..f161ff073f3
--- /dev/null
+++ b/library/std/src/sys/env/common.rs
@@ -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()
+    }
+}
diff --git a/library/std/src/sys/env/hermit.rs b/library/std/src/sys/env/hermit.rs
index 4c7d7e80a35..445ecdeb6a3 100644
--- a/library/std/src/sys/env/hermit.rs
+++ b/library/std/src/sys/env/hermit.rs
@@ -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> {
diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs
index 0ae7ef53add..d81ff875c83 100644
--- a/library/std/src/sys/env/mod.rs
+++ b/library/std/src/sys/env/mod.rs
@@ -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;
diff --git a/library/std/src/sys/env/sgx.rs b/library/std/src/sys/env/sgx.rs
index 7a48fb1872b..85be9cd6ad4 100644
--- a/library/std/src/sys/env/sgx.rs
+++ b/library/std/src/sys/env/sgx.rs
@@ -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> {
diff --git a/library/std/src/sys/env/solid.rs b/library/std/src/sys/env/solid.rs
index 0eb801c996a..ea77fc3c119 100644
--- a/library/std/src/sys/env/solid.rs
+++ b/library/std/src/sys/env/solid.rs
@@ -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)> {
diff --git a/library/std/src/sys/env/uefi.rs b/library/std/src/sys/env/uefi.rs
index a26305acf8e..1561df41cac 100644
--- a/library/std/src/sys/env/uefi.rs
+++ b/library/std/src/sys/env/uefi.rs
@@ -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> {
diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs
index 73aacfcad3b..78c7af65f9e 100644
--- a/library/std/src/sys/env/unix.rs
+++ b/library/std/src/sys/env/unix.rs
@@ -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)> {
diff --git a/library/std/src/sys/env/wasi.rs b/library/std/src/sys/env/wasi.rs
index 6bdb2d5a547..3719f9db51e 100644
--- a/library/std/src/sys/env/wasi.rs
+++ b/library/std/src/sys/env/wasi.rs
@@ -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
diff --git a/library/std/src/sys/env/xous.rs b/library/std/src/sys/env/xous.rs
index d5b8a1c7fb4..232a3dafb0b 100644
--- a/library/std/src/sys/env/xous.rs
+++ b/library/std/src/sys/env/xous.rs
@@ -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> {