about summary refs log tree commit diff
path: root/library/std/src/env.rs
diff options
context:
space:
mode:
authorThalia Archibald <thalia@archibald.dev>2025-04-12 06:18:53 -0700
committerThalia Archibald <thalia@archibald.dev>2025-05-01 15:18:15 -0700
commit28deaa6e0e7993f963b3bb44bb235c7682ce0cf3 (patch)
tree8001060a0da0b273e6729e2bc16924d3b38aea54 /library/std/src/env.rs
parent0c33fe2c3d3eecadd17a84b110bb067288a64f1c (diff)
downloadrust-28deaa6e0e7993f963b3bb44bb235c7682ce0cf3.tar.gz
rust-28deaa6e0e7993f963b3bb44bb235c7682ce0cf3.zip
Delegate to inner `vec::IntoIter` from `env::ArgsOs`
Delegate from `std::env::ArgsOs` to the methods of the inner
platform-specific iterators, when it would be more efficient than just
using the default methods of its own impl. Most platforms use
`vec::IntoIter` as the inner type, so prioritize delegating to the
methods it provides.

`std::env::Args` is implemented atop `std::env::ArgsOs` and performs
UTF-8 validation with a panic for invalid data. This is a visible effect
which users certainly rely on, so we can't skip any arguments. Any
further iterator methods would skip some elements, so no change is
needed for that type.

Add `#[inline]` for any methods which simply wrap the inner iterator.
Diffstat (limited to 'library/std/src/env.rs')
-rw-r--r--library/std/src/env.rs73
1 files changed, 72 insertions, 1 deletions
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 1593969e114..ce2dc795220 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -12,9 +12,11 @@
 
 use crate::error::Error;
 use crate::ffi::{OsStr, OsString};
+use crate::num::NonZero;
+use crate::ops::Try;
 use crate::path::{Path, PathBuf};
 use crate::sys::{env as env_imp, os as os_imp};
-use crate::{fmt, io, sys};
+use crate::{array, fmt, io, sys};
 
 /// Returns the current working directory as a [`PathBuf`].
 ///
@@ -872,19 +874,36 @@ impl !Sync for Args {}
 #[stable(feature = "env", since = "1.0.0")]
 impl Iterator for Args {
     type Item = String;
+
     fn next(&mut self) -> Option<String> {
         self.inner.next().map(|s| s.into_string().unwrap())
     }
+
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    // Methods which skip args cannot simply delegate to the inner iterator,
+    // because `env::args` states that we will "panic during iteration if any
+    // argument to the process is not valid Unicode".
+    //
+    // This offers two possible interpretations:
+    // - a skipped argument is never encountered "during iteration"
+    // - even a skipped argument is encountered "during iteration"
+    //
+    // As a panic can be observed, we err towards validating even skipped
+    // arguments for now, though this is not explicitly promised by the API.
 }
 
 #[stable(feature = "env", since = "1.0.0")]
 impl ExactSizeIterator for Args {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
+
+    #[inline]
     fn is_empty(&self) -> bool {
         self.inner.is_empty()
     }
@@ -914,19 +933,65 @@ impl !Sync for ArgsOs {}
 #[stable(feature = "env", since = "1.0.0")]
 impl Iterator for ArgsOs {
     type Item = OsString;
+
+    #[inline]
     fn next(&mut self) -> Option<OsString> {
         self.inner.next()
     }
+
+    #[inline]
+    fn next_chunk<const N: usize>(
+        &mut self,
+    ) -> Result<[OsString; N], array::IntoIter<OsString, N>> {
+        self.inner.next_chunk()
+    }
+
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.inner.len()
+    }
+
+    #[inline]
+    fn last(self) -> Option<OsString> {
+        self.inner.last()
+    }
+
+    #[inline]
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.inner.advance_by(n)
+    }
+
+    #[inline]
+    fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        self.inner.try_fold(init, f)
+    }
+
+    #[inline]
+    fn fold<B, F>(self, init: B, f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        self.inner.fold(init, f)
+    }
 }
 
 #[stable(feature = "env", since = "1.0.0")]
 impl ExactSizeIterator for ArgsOs {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
+
+    #[inline]
     fn is_empty(&self) -> bool {
         self.inner.is_empty()
     }
@@ -934,9 +999,15 @@ impl ExactSizeIterator for ArgsOs {
 
 #[stable(feature = "env_iterators", since = "1.12.0")]
 impl DoubleEndedIterator for ArgsOs {
+    #[inline]
     fn next_back(&mut self) -> Option<OsString> {
         self.inner.next_back()
     }
+
+    #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.inner.advance_back_by(n)
+    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]