Skip to content

Commit 1aa8dad

Browse files
committed
DoubleEndedIterator for Args
The number of arguments given to a process is always known, which makes implementing DoubleEndedIterator possible. That way, the Iterator::rev() method becomes usable, among others. Signed-off-by: Sebastian Thiel <byronimo@gmail.com> Tidy for DoubleEndedIterator I chose to not create a new feature for it, even though technically, this makes me lie about the original availability of the implementation. Verify with @alexchrichton Setup feature flag for new std::env::Args iterators Add test for Args reverse iterator It's somewhat depending on the input of the test program, but made in such a way that should be somewhat flexible to changes to the way it is called. Deduplicate windows ArgsOS code for DEI DEI = DoubleEndedIterator Move env::args().rev() test to run-pass It must be controlling it's arguments for full isolation. Remove superfluous feature name Assert all arguments returned by env::args().rev() Let's be very sure it works as we expect, why take chances. Fix rval of os_string_from_ptr A trait cannot be returned, but only the corresponding object. Deref pointers to actually operate on the argument Put unsafe to correct location
1 parent 728eea7 commit 1aa8dad

File tree

4 files changed

+76
-10
lines changed

4 files changed

+76
-10
lines changed

src/libstd/env.rs

+11
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,13 @@ impl ExactSizeIterator for Args {
587587
fn len(&self) -> usize { self.inner.len() }
588588
}
589589

590+
#[stable(feature = "env_iterators", since = "1.11.0")]
591+
impl DoubleEndedIterator for Args {
592+
fn next_back(&mut self) -> Option<String> {
593+
self.inner.next_back().map(|s| s.into_string().unwrap())
594+
}
595+
}
596+
590597
#[stable(feature = "env", since = "1.0.0")]
591598
impl Iterator for ArgsOs {
592599
type Item = OsString;
@@ -599,6 +606,10 @@ impl ExactSizeIterator for ArgsOs {
599606
fn len(&self) -> usize { self.inner.len() }
600607
}
601608

609+
#[stable(feature = "env_iterators", since = "1.11.0")]
610+
impl DoubleEndedIterator for ArgsOs {
611+
fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() }
612+
}
602613
/// Constants associated with the current target
603614
#[stable(feature = "env", since = "1.0.0")]
604615
pub mod consts {

src/libstd/sys/unix/os.rs

+4
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ impl ExactSizeIterator for Args {
308308
fn len(&self) -> usize { self.iter.len() }
309309
}
310310

311+
impl DoubleEndedIterator for Args {
312+
fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
313+
}
314+
311315
/// Returns the command line arguments
312316
///
313317
/// Returns a list of the command line arguments.

src/libstd/sys/windows/os.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -278,23 +278,30 @@ pub struct Args {
278278
cur: *mut *mut u16,
279279
}
280280

281+
unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString {
282+
let mut len = 0;
283+
while *ptr.offset(len) != 0 { len += 1; }
284+
285+
// Push it onto the list.
286+
let ptr = ptr as *const u16;
287+
let buf = slice::from_raw_parts(ptr, len as usize);
288+
OsStringExt::from_wide(buf)
289+
}
290+
281291
impl Iterator for Args {
282292
type Item = OsString;
283293
fn next(&mut self) -> Option<OsString> {
284-
self.range.next().map(|i| unsafe {
285-
let ptr = *self.cur.offset(i);
286-
let mut len = 0;
287-
while *ptr.offset(len) != 0 { len += 1; }
288-
289-
// Push it onto the list.
290-
let ptr = ptr as *const u16;
291-
let buf = slice::from_raw_parts(ptr, len as usize);
292-
OsStringExt::from_wide(buf)
293-
})
294+
self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
294295
}
295296
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
296297
}
297298

299+
impl DoubleEndedIterator for Args {
300+
fn next_back(&mut self) -> Option<OsString> {
301+
self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } )
302+
}
303+
}
304+
298305
impl ExactSizeIterator for Args {
299306
fn len(&self) -> usize { self.range.len() }
300307
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::env::args;
12+
use std::process::Command;
13+
14+
fn assert_reverse_iterator_for_program_arguments(program_name: &str) {
15+
let args: Vec<_> = args().rev().collect();
16+
17+
assert!(args.len() == 4);
18+
assert_eq!(args[0], "c");
19+
assert_eq!(args[1], "b");
20+
assert_eq!(args[2], "a");
21+
assert_eq!(args[3], program_name);
22+
23+
println!("passed");
24+
}
25+
26+
fn main() {
27+
let mut args = args();
28+
let me = args.next().unwrap();
29+
30+
if let Some(_) = args.next() {
31+
assert_reverse_iterator_for_program_arguments(&me);
32+
return
33+
}
34+
35+
let output = Command::new(&me)
36+
.arg("a")
37+
.arg("b")
38+
.arg("c")
39+
.output()
40+
.unwrap();
41+
assert!(output.status.success());
42+
assert!(output.stderr.is_empty());
43+
assert_eq!(output.stdout, b"passed\n");
44+
}

0 commit comments

Comments
 (0)