|
1 |
| -use crate::ffi::OsString; |
2 |
| -use crate::fmt; |
| 1 | +use crate::ffi::{OsStr, OsString}; |
3 | 2 | use crate::num::NonZero;
|
4 |
| -use crate::sys::os_str; |
| 3 | +use crate::sync::OnceLock; |
5 | 4 | use crate::sys::pal::{WORD_SIZE, abi};
|
6 |
| -use crate::sys_common::FromInner; |
7 |
| - |
8 |
| -#[derive(Clone)] |
9 |
| -pub struct Args { |
10 |
| - front: usize, |
11 |
| - back: usize, |
12 |
| -} |
| 5 | +use crate::{fmt, ptr, slice}; |
13 | 6 |
|
14 | 7 | pub fn args() -> Args {
|
15 |
| - let count = unsafe { abi::sys_argc() }; |
16 |
| - Args { front: 0, back: count } |
| 8 | + Args { iter: ARGS.get_or_init(|| get_args()).iter() } |
17 | 9 | }
|
18 | 10 |
|
19 |
| -impl Args { |
20 |
| - /// Use sys_argv to get the arg at the requested index. Does not check that i is less than argc |
21 |
| - /// and will not return if the index is out of bounds. |
22 |
| - fn argv(i: usize) -> OsString { |
23 |
| - let arg_len = unsafe { abi::sys_argv(crate::ptr::null_mut(), 0, i) }; |
| 11 | +fn get_args() -> Vec<&'static OsStr> { |
| 12 | + let argc = unsafe { abi::sys_argc() }; |
| 13 | + let mut args = Vec::with_capacity(argc); |
| 14 | + |
| 15 | + for i in 0..argc { |
| 16 | + // Get the size of the argument then the data. |
| 17 | + let arg_len = unsafe { abi::sys_argv(ptr::null_mut(), 0, i) }; |
24 | 18 |
|
25 | 19 | let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE;
|
26 | 20 | let words = unsafe { abi::sys_alloc_words(arg_len_words) };
|
27 | 21 |
|
28 | 22 | let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) };
|
29 | 23 | debug_assert_eq!(arg_len, arg_len2);
|
30 | 24 |
|
31 |
| - // Convert to OsString. |
32 |
| - // |
33 |
| - // FIXME: We can probably get rid of the extra copy here if we |
34 |
| - // reimplement "os_str" instead of just using the generic unix |
35 |
| - // "os_str". |
36 |
| - let arg_bytes: &[u8] = |
37 |
| - unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, arg_len) }; |
38 |
| - OsString::from_inner(os_str::Buf { inner: arg_bytes.to_vec() }) |
| 25 | + let arg_bytes = unsafe { slice::from_raw_parts(words.cast(), arg_len) }; |
| 26 | + args.push(unsafe { OsStr::from_encoded_bytes_unchecked(arg_bytes) }); |
39 | 27 | }
|
| 28 | + args |
| 29 | +} |
| 30 | + |
| 31 | +static ARGS: OnceLock<Vec<&'static OsStr>> = OnceLock::new(); |
| 32 | + |
| 33 | +pub struct Args { |
| 34 | + iter: slice::Iter<'static, &'static OsStr>, |
40 | 35 | }
|
41 | 36 |
|
42 | 37 | impl !Send for Args {}
|
43 | 38 | impl !Sync for Args {}
|
44 | 39 |
|
45 | 40 | impl fmt::Debug for Args {
|
46 | 41 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
47 |
| - f.debug_list().entries(self.clone()).finish() |
| 42 | + self.iter.as_slice().fmt(f) |
48 | 43 | }
|
49 | 44 | }
|
50 | 45 |
|
51 | 46 | impl Iterator for Args {
|
52 | 47 | type Item = OsString;
|
53 | 48 |
|
54 |
| - #[inline] |
55 | 49 | fn next(&mut self) -> Option<OsString> {
|
56 |
| - if self.front == self.back { |
57 |
| - None |
58 |
| - } else { |
59 |
| - let arg = Self::argv(self.front); |
60 |
| - self.front += 1; |
61 |
| - Some(arg) |
62 |
| - } |
| 50 | + self.iter.next().map(|arg| arg.to_os_string()) |
63 | 51 | }
|
64 | 52 |
|
65 | 53 | #[inline]
|
66 | 54 | fn size_hint(&self) -> (usize, Option<usize>) {
|
67 |
| - let len = self.len(); |
68 |
| - (len, Some(len)) |
| 55 | + self.iter.size_hint() |
69 | 56 | }
|
70 | 57 |
|
71 | 58 | #[inline]
|
72 | 59 | fn count(self) -> usize {
|
73 |
| - self.len() |
| 60 | + self.iter.len() |
74 | 61 | }
|
75 | 62 |
|
76 |
| - #[inline] |
77 |
| - fn last(mut self) -> Option<OsString> { |
78 |
| - self.next_back() |
| 63 | + fn last(self) -> Option<OsString> { |
| 64 | + self.iter.last().map(|arg| arg.to_os_string()) |
79 | 65 | }
|
80 | 66 |
|
81 | 67 | #[inline]
|
82 | 68 | fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
83 |
| - let step_size = self.len().min(n); |
84 |
| - self.front += step_size; |
85 |
| - NonZero::new(n - step_size).map_or(Ok(()), Err) |
| 69 | + self.iter.advance_by(n) |
86 | 70 | }
|
87 | 71 | }
|
88 | 72 |
|
89 | 73 | impl DoubleEndedIterator for Args {
|
90 |
| - #[inline] |
91 | 74 | fn next_back(&mut self) -> Option<OsString> {
|
92 |
| - if self.back == self.front { |
93 |
| - None |
94 |
| - } else { |
95 |
| - self.back -= 1; |
96 |
| - Some(Self::argv(self.back)) |
97 |
| - } |
| 75 | + self.iter.next_back().map(|arg| arg.to_os_string()) |
98 | 76 | }
|
99 | 77 |
|
100 | 78 | #[inline]
|
101 | 79 | fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
102 |
| - let step_size = self.len().min(n); |
103 |
| - self.back -= step_size; |
104 |
| - NonZero::new(n - step_size).map_or(Ok(()), Err) |
| 80 | + self.iter.advance_back_by(n) |
105 | 81 | }
|
106 | 82 | }
|
107 | 83 |
|
108 | 84 | impl ExactSizeIterator for Args {
|
109 | 85 | #[inline]
|
110 | 86 | fn len(&self) -> usize {
|
111 |
| - self.back - self.front |
| 87 | + self.iter.len() |
112 | 88 | }
|
113 | 89 |
|
114 | 90 | #[inline]
|
115 | 91 | fn is_empty(&self) -> bool {
|
116 |
| - self.front == self.back |
| 92 | + self.iter.is_empty() |
117 | 93 | }
|
118 | 94 | }
|
0 commit comments