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