safa_api/process/
args.rs

1//! Wrapper around the arguments passed to the program.
2//! api should be initialized before use see [`super::init`]
3
4use core::{cell::UnsafeCell, mem::MaybeUninit, ptr::NonNull};
5use safa_abi::raw::{NonNullSlice, Optional};
6
7// args
8
9#[derive(Debug, Clone, Copy)]
10pub(super) struct RawArgs {
11    args: NonNull<[NonNullSlice<u8>]>,
12}
13
14impl RawArgs {
15    pub const fn new(args: NonNull<[NonNullSlice<u8>]>) -> Self {
16        Self { args }
17    }
18
19    fn len(&self) -> usize {
20        unsafe { self.args.as_ref().len() }
21    }
22
23    fn get(&self, index: usize) -> Option<NonNullSlice<u8>> {
24        unsafe { self.args.as_ref().get(index).copied() }
25    }
26
27    unsafe fn into_slice(self) -> &'static [NonNullSlice<u8>] {
28        unsafe { self.args.as_ref() }
29    }
30}
31
32pub(super) struct RawArgsStatic(UnsafeCell<MaybeUninit<Option<RawArgs>>>);
33unsafe impl Sync for RawArgsStatic {}
34
35impl RawArgsStatic {
36    pub const fn new() -> Self {
37        Self(UnsafeCell::new(MaybeUninit::uninit()))
38    }
39
40    pub unsafe fn init(&self, args: Option<RawArgs>) {
41        unsafe {
42            self.0.get().write(MaybeUninit::new(args));
43        }
44    }
45
46    unsafe fn get(&self, index: usize) -> Option<NonNullSlice<u8>> {
47        unsafe { (*self.0.get()).assume_init()?.get(index) }
48    }
49
50    unsafe fn len(&self) -> usize {
51        if let Some(args) = unsafe { (*self.0.get()).assume_init() } {
52            args.len()
53        } else {
54            0
55        }
56    }
57
58    unsafe fn get_raw(&self) -> Option<RawArgs> {
59        unsafe { (*self.0.get()).assume_init() }
60    }
61
62    pub unsafe fn as_slice(&self) -> &'static [NonNullSlice<u8>] {
63        unsafe {
64            if let Some(raw) = self.get_raw() {
65                raw.into_slice()
66            } else {
67                &mut []
68            }
69        }
70    }
71}
72
73pub(super) static RAW_ARGS: RawArgsStatic = RawArgsStatic::new();
74
75/// Get the number of arguments passed to the program.
76#[cfg_attr(
77    not(any(feature = "std", feature = "rustc-dep-of-std")),
78    unsafe(no_mangle)
79)]
80#[inline(always)]
81pub extern "C" fn sysget_argc() -> usize {
82    unsafe { RAW_ARGS.len() }
83}
84
85/// Get the argument at the given index.
86#[cfg_attr(
87    not(any(feature = "std", feature = "rustc-dep-of-std")),
88    unsafe(no_mangle)
89)]
90#[inline(always)]
91pub extern "C" fn sysget_arg(index: usize) -> Optional<NonNullSlice<u8>> {
92    unsafe { RAW_ARGS.get(index).into() }
93}
94
95/// An iterator over the arguments passed to the program.
96pub struct ArgsIter {
97    args: &'static [NonNullSlice<u8>],
98    index: usize,
99}
100
101impl ArgsIter {
102    pub fn get() -> Self {
103        let args = unsafe { RAW_ARGS.as_slice() };
104        Self { args, index: 0 }
105    }
106
107    pub fn get_index(&self, index: usize) -> Option<NonNullSlice<u8>> {
108        self.args.get(index).copied()
109    }
110
111    pub fn next(&mut self) -> Option<NonNullSlice<u8>> {
112        if self.index < self.args.len() {
113            let arg = self.args[self.index];
114            self.index += 1;
115            Some(arg)
116        } else {
117            None
118        }
119    }
120    /// The total amount of args in the iterator before calling [`Self::next`]
121    pub fn total_len(&self) -> usize {
122        self.args.len()
123    }
124    /// The amount of remaining args in the iterator
125    pub fn len(&self) -> usize {
126        self.total_len() - self.index
127    }
128}