Skip to content

Commit ac00d49

Browse files
committed
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.
1 parent 0c33fe2 commit ac00d49

File tree

5 files changed

+199
-21
lines changed

5 files changed

+199
-21
lines changed

library/std/src/env.rs

+64-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212

1313
use crate::error::Error;
1414
use crate::ffi::{OsStr, OsString};
15+
use crate::num::NonZero;
16+
use crate::ops::Try;
1517
use crate::path::{Path, PathBuf};
1618
use crate::sys::{env as env_imp, os as os_imp};
17-
use crate::{fmt, io, sys};
19+
use crate::{array, fmt, io, sys};
1820

1921
/// Returns the current working directory as a [`PathBuf`].
2022
///
@@ -872,19 +874,28 @@ impl !Sync for Args {}
872874
#[stable(feature = "env", since = "1.0.0")]
873875
impl Iterator for Args {
874876
type Item = String;
877+
875878
fn next(&mut self) -> Option<String> {
876879
self.inner.next().map(|s| s.into_string().unwrap())
877880
}
881+
882+
#[inline]
878883
fn size_hint(&self) -> (usize, Option<usize>) {
879884
self.inner.size_hint()
880885
}
886+
887+
// Methods which skip args cannot simply delegate to the inner iterator,
888+
// because UTF-8 validation needs to be performed for every argument.
881889
}
882890

883891
#[stable(feature = "env", since = "1.0.0")]
884892
impl ExactSizeIterator for Args {
893+
#[inline]
885894
fn len(&self) -> usize {
886895
self.inner.len()
887896
}
897+
898+
#[inline]
888899
fn is_empty(&self) -> bool {
889900
self.inner.is_empty()
890901
}
@@ -914,29 +925,81 @@ impl !Sync for ArgsOs {}
914925
#[stable(feature = "env", since = "1.0.0")]
915926
impl Iterator for ArgsOs {
916927
type Item = OsString;
928+
929+
#[inline]
917930
fn next(&mut self) -> Option<OsString> {
918931
self.inner.next()
919932
}
933+
934+
#[inline]
935+
fn next_chunk<const N: usize>(
936+
&mut self,
937+
) -> Result<[OsString; N], array::IntoIter<OsString, N>> {
938+
self.inner.next_chunk()
939+
}
940+
941+
#[inline]
920942
fn size_hint(&self) -> (usize, Option<usize>) {
921943
self.inner.size_hint()
922944
}
945+
946+
#[inline]
947+
fn count(self) -> usize {
948+
self.inner.len()
949+
}
950+
951+
#[inline]
952+
fn last(self) -> Option<OsString> {
953+
self.inner.last()
954+
}
955+
956+
#[inline]
957+
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
958+
self.inner.advance_by(n)
959+
}
960+
961+
#[inline]
962+
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
963+
where
964+
F: FnMut(B, Self::Item) -> R,
965+
R: Try<Output = B>,
966+
{
967+
self.inner.try_fold(init, f)
968+
}
969+
970+
#[inline]
971+
fn fold<B, F>(self, init: B, f: F) -> B
972+
where
973+
F: FnMut(B, Self::Item) -> B,
974+
{
975+
self.inner.fold(init, f)
976+
}
923977
}
924978

925979
#[stable(feature = "env", since = "1.0.0")]
926980
impl ExactSizeIterator for ArgsOs {
981+
#[inline]
927982
fn len(&self) -> usize {
928983
self.inner.len()
929984
}
985+
986+
#[inline]
930987
fn is_empty(&self) -> bool {
931988
self.inner.is_empty()
932989
}
933990
}
934991

935992
#[stable(feature = "env_iterators", since = "1.12.0")]
936993
impl DoubleEndedIterator for ArgsOs {
994+
#[inline]
937995
fn next_back(&mut self) -> Option<OsString> {
938996
self.inner.next_back()
939997
}
998+
999+
#[inline]
1000+
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
1001+
self.inner.advance_back_by(n)
1002+
}
9401003
}
9411004

9421005
#[stable(feature = "std_debug", since = "1.16.0")]

library/std/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@
301301
#![feature(formatting_options)]
302302
#![feature(if_let_guard)]
303303
#![feature(intra_doc_pointers)]
304+
#![feature(iter_advance_by)]
305+
#![feature(iter_next_chunk)]
304306
#![feature(lang_items)]
305307
#![feature(let_chains)]
306308
#![feature(link_cfg)]
@@ -321,6 +323,7 @@
321323
#![feature(strict_provenance_lints)]
322324
#![feature(thread_local)]
323325
#![feature(try_blocks)]
326+
#![feature(try_trait_v2)]
324327
#![feature(type_alias_impl_trait)]
325328
// tidy-alphabetical-end
326329
//

library/std/src/sys/args/common.rs

+62-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::ffi::OsString;
2-
use crate::{fmt, vec};
2+
use crate::num::NonZero;
3+
use crate::ops::Try;
4+
use crate::{array, fmt, vec};
35

46
pub struct Args {
57
iter: vec::IntoIter<OsString>,
@@ -9,6 +11,7 @@ impl !Send for Args {}
911
impl !Sync for Args {}
1012

1113
impl Args {
14+
#[inline]
1215
pub(super) fn new(args: Vec<OsString>) -> Self {
1316
Args { iter: args.into_iter() }
1417
}
@@ -22,22 +25,77 @@ impl fmt::Debug for Args {
2225

2326
impl Iterator for Args {
2427
type Item = OsString;
28+
29+
#[inline]
2530
fn next(&mut self) -> Option<OsString> {
2631
self.iter.next()
2732
}
33+
34+
#[inline]
35+
fn next_chunk<const N: usize>(
36+
&mut self,
37+
) -> Result<[OsString; N], array::IntoIter<OsString, N>> {
38+
self.iter.next_chunk()
39+
}
40+
41+
#[inline]
2842
fn size_hint(&self) -> (usize, Option<usize>) {
2943
self.iter.size_hint()
3044
}
31-
}
3245

33-
impl ExactSizeIterator for Args {
34-
fn len(&self) -> usize {
46+
#[inline]
47+
fn count(self) -> usize {
3548
self.iter.len()
3649
}
50+
51+
#[inline]
52+
fn last(mut self) -> Option<OsString> {
53+
self.iter.next_back()
54+
}
55+
56+
#[inline]
57+
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
58+
self.iter.advance_by(n)
59+
}
60+
61+
#[inline]
62+
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
63+
where
64+
F: FnMut(B, Self::Item) -> R,
65+
R: Try<Output = B>,
66+
{
67+
self.iter.try_fold(init, f)
68+
}
69+
70+
#[inline]
71+
fn fold<B, F>(self, init: B, f: F) -> B
72+
where
73+
F: FnMut(B, Self::Item) -> B,
74+
{
75+
self.iter.fold(init, f)
76+
}
3777
}
3878

3979
impl DoubleEndedIterator for Args {
80+
#[inline]
4081
fn next_back(&mut self) -> Option<OsString> {
4182
self.iter.next_back()
4283
}
84+
85+
#[inline]
86+
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
87+
self.iter.advance_back_by(n)
88+
}
89+
}
90+
91+
impl ExactSizeIterator for Args {
92+
#[inline]
93+
fn len(&self) -> usize {
94+
self.iter.len()
95+
}
96+
97+
#[inline]
98+
fn is_empty(&self) -> bool {
99+
self.iter.is_empty()
100+
}
43101
}

library/std/src/sys/args/sgx.rs

+58-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers
22

33
use crate::ffi::OsString;
4+
use crate::num::NonZero;
5+
use crate::ops::Try;
46
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
57
use crate::sys::os_str::Buf;
68
use crate::sys::pal::abi::usercalls::alloc;
@@ -28,35 +30,81 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
2830

2931
pub fn args() -> Args {
3032
let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() };
31-
if let Some(args) = args { Args(args.iter()) } else { Args([].iter()) }
33+
let slice = args.map(|args| args.as_slice()).unwrap_or(&[]);
34+
Args { iter: slice.iter() }
3235
}
3336

34-
pub struct Args(slice::Iter<'static, OsString>);
37+
pub struct Args {
38+
iter: slice::Iter<'static, OsString>,
39+
}
3540

3641
impl fmt::Debug for Args {
3742
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38-
self.0.as_slice().fmt(f)
43+
self.iter.as_slice().fmt(f)
3944
}
4045
}
4146

4247
impl Iterator for Args {
4348
type Item = OsString;
49+
4450
fn next(&mut self) -> Option<OsString> {
45-
self.0.next().cloned()
51+
self.iter.next().cloned()
4652
}
53+
54+
#[inline]
4755
fn size_hint(&self) -> (usize, Option<usize>) {
48-
self.0.size_hint()
56+
self.iter.size_hint()
4957
}
50-
}
5158

52-
impl ExactSizeIterator for Args {
53-
fn len(&self) -> usize {
54-
self.0.len()
59+
#[inline]
60+
fn count(self) -> usize {
61+
self.iter.len()
62+
}
63+
64+
fn last(self) -> Option<OsString> {
65+
self.iter.last().cloned()
66+
}
67+
68+
#[inline]
69+
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
70+
self.iter.advance_by(n)
71+
}
72+
73+
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
74+
where
75+
F: FnMut(B, Self::Item) -> R,
76+
R: Try<Output = B>,
77+
{
78+
self.iter.by_ref().cloned().try_fold(init, f)
79+
}
80+
81+
fn fold<B, F>(self, init: B, f: F) -> B
82+
where
83+
F: FnMut(B, Self::Item) -> B,
84+
{
85+
self.iter.cloned().fold(init, f)
5586
}
5687
}
5788

5889
impl DoubleEndedIterator for Args {
5990
fn next_back(&mut self) -> Option<OsString> {
60-
self.0.next_back().cloned()
91+
self.iter.next_back().cloned()
92+
}
93+
94+
#[inline]
95+
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
96+
self.iter.advance_back_by(n)
97+
}
98+
}
99+
100+
impl ExactSizeIterator for Args {
101+
#[inline]
102+
fn len(&self) -> usize {
103+
self.iter.len()
104+
}
105+
106+
#[inline]
107+
fn is_empty(&self) -> bool {
108+
self.iter.is_empty()
61109
}
62110
}

library/std/src/sys/args/unsupported.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,28 @@ impl fmt::Debug for Args {
1515

1616
impl Iterator for Args {
1717
type Item = OsString;
18+
19+
#[inline]
1820
fn next(&mut self) -> Option<OsString> {
1921
None
2022
}
23+
24+
#[inline]
2125
fn size_hint(&self) -> (usize, Option<usize>) {
2226
(0, Some(0))
2327
}
2428
}
2529

26-
impl ExactSizeIterator for Args {
27-
fn len(&self) -> usize {
28-
0
29-
}
30-
}
31-
3230
impl DoubleEndedIterator for Args {
31+
#[inline]
3332
fn next_back(&mut self) -> Option<OsString> {
3433
None
3534
}
3635
}
36+
37+
impl ExactSizeIterator for Args {
38+
#[inline]
39+
fn len(&self) -> usize {
40+
0
41+
}
42+
}

0 commit comments

Comments
 (0)