about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/std/src/sys/args/zkvm.rs86
1 files changed, 31 insertions, 55 deletions
diff --git a/library/std/src/sys/args/zkvm.rs b/library/std/src/sys/args/zkvm.rs
index e4b1ad540ac..d26bf1eaff9 100644
--- a/library/std/src/sys/args/zkvm.rs
+++ b/library/std/src/sys/args/zkvm.rs
@@ -1,26 +1,20 @@
-use crate::ffi::OsString;
-use crate::fmt;
+use crate::ffi::{OsStr, OsString};
 use crate::num::NonZero;
-use crate::sys::os_str;
+use crate::sync::OnceLock;
 use crate::sys::pal::{WORD_SIZE, abi};
-use crate::sys_common::FromInner;
-
-#[derive(Clone)]
-pub struct Args {
-    front: usize,
-    back: usize,
-}
+use crate::{fmt, ptr, slice};
 
 pub fn args() -> Args {
-    let count = unsafe { abi::sys_argc() };
-    Args { front: 0, back: count }
+    Args { iter: ARGS.get_or_init(|| get_args()).iter() }
 }
 
-impl Args {
-    /// Use sys_argv to get the arg at the requested index. Does not check that i is less than argc
-    /// and will not return if the index is out of bounds.
-    fn argv(i: usize) -> OsString {
-        let arg_len = unsafe { abi::sys_argv(crate::ptr::null_mut(), 0, i) };
+fn get_args() -> Vec<&'static OsStr> {
+    let argc = unsafe { abi::sys_argc() };
+    let mut args = Vec::with_capacity(argc);
+
+    for i in 0..argc {
+        // Get the size of the argument then the data.
+        let arg_len = unsafe { abi::sys_argv(ptr::null_mut(), 0, i) };
 
         let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE;
         let words = unsafe { abi::sys_alloc_words(arg_len_words) };
@@ -28,15 +22,16 @@ impl Args {
         let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) };
         debug_assert_eq!(arg_len, arg_len2);
 
-        // Convert to OsString.
-        //
-        // FIXME: We can probably get rid of the extra copy here if we
-        // reimplement "os_str" instead of just using the generic unix
-        // "os_str".
-        let arg_bytes: &[u8] =
-            unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, arg_len) };
-        OsString::from_inner(os_str::Buf { inner: arg_bytes.to_vec() })
+        let arg_bytes = unsafe { slice::from_raw_parts(words.cast(), arg_len) };
+        args.push(unsafe { OsStr::from_encoded_bytes_unchecked(arg_bytes) });
     }
+    args
+}
+
+static ARGS: OnceLock<Vec<&'static OsStr>> = OnceLock::new();
+
+pub struct Args {
+    iter: slice::Iter<'static, &'static OsStr>,
 }
 
 impl !Send for Args {}
@@ -44,75 +39,56 @@ impl !Sync for Args {}
 
 impl fmt::Debug for Args {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(self.clone()).finish()
+        self.iter.as_slice().fmt(f)
     }
 }
 
 impl Iterator for Args {
     type Item = OsString;
 
-    #[inline]
     fn next(&mut self) -> Option<OsString> {
-        if self.front == self.back {
-            None
-        } else {
-            let arg = Self::argv(self.front);
-            self.front += 1;
-            Some(arg)
-        }
+        self.iter.next().map(|arg| arg.to_os_string())
     }
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let len = self.len();
-        (len, Some(len))
+        self.iter.size_hint()
     }
 
     #[inline]
     fn count(self) -> usize {
-        self.len()
+        self.iter.len()
     }
 
-    #[inline]
-    fn last(mut self) -> Option<OsString> {
-        self.next_back()
+    fn last(self) -> Option<OsString> {
+        self.iter.last().map(|arg| arg.to_os_string())
     }
 
     #[inline]
     fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
-        let step_size = self.len().min(n);
-        self.front += step_size;
-        NonZero::new(n - step_size).map_or(Ok(()), Err)
+        self.iter.advance_by(n)
     }
 }
 
 impl DoubleEndedIterator for Args {
-    #[inline]
     fn next_back(&mut self) -> Option<OsString> {
-        if self.back == self.front {
-            None
-        } else {
-            self.back -= 1;
-            Some(Self::argv(self.back))
-        }
+        self.iter.next_back().map(|arg| arg.to_os_string())
     }
 
     #[inline]
     fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
-        let step_size = self.len().min(n);
-        self.back -= step_size;
-        NonZero::new(n - step_size).map_or(Ok(()), Err)
+        self.iter.advance_back_by(n)
     }
 }
 
 impl ExactSizeIterator for Args {
     #[inline]
     fn len(&self) -> usize {
-        self.back - self.front
+        self.iter.len()
     }
 
     #[inline]
     fn is_empty(&self) -> bool {
-        self.front == self.back
+        self.iter.is_empty()
     }
 }