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