c_ffi/
args.rs

1//! C style arguments wrapper
2
3#[derive(Copy, Clone)]
4///Wrapper over C-style arguments
5///
6///## Example:
7///
8///On most targets you can supply own C-style main function.
9///
10///One of the benefits is that it is no longer necessary to rely on allocating `std::env::Args`
11///
12///```rust
13///#![no_main]
14///
15///#[no_mangle]
16///pub unsafe extern fn main(argc: std::os::raw::c_int, argv: *const *const u8) -> std::os::raw::c_int {
17///    let args = c_ffi::Args::new(argc as isize, argv).expect("To get function arguments");
18///
19///    0
20///}
21///```
22pub struct Args {
23    argc: usize,
24    argv: *const *const u8,
25}
26
27impl Args {
28    ///Creates new instance, but verifies that each string inside are UTF-8.
29    ///
30    ///On error returns pair: `(string index, Utf8Error)`
31    ///
32    ///The function is safe as long as you pass C style main function arguments.
33    pub unsafe fn new(argc: isize, argv: *const *const u8) -> Result<Self, (usize, core::str::Utf8Error)> {
34        debug_assert!(argc > 0);
35        debug_assert!(!argv.is_null());
36
37        let this = Args {
38            argc: argc as usize,
39            argv,
40        };
41
42        let args = this.as_slice();
43        for idx in 0..this.argc {
44            let arg = *args.get_unchecked(idx);
45            if let Err(error) = crate::c_str_to_rust(arg) {
46                return Err((idx, error));
47            }
48        }
49
50        Ok(this)
51    }
52
53    #[inline(always)]
54    ///Unchecked version of `Args::new`
55    ///
56    ///Do it on your own risk
57    pub unsafe fn new_unchecked(argc: isize, argv: *const *const u8) -> Self {
58        Args {
59            argc: argc as usize,
60            argv,
61        }
62    }
63
64    #[inline(always)]
65    ///Returns slice of raw C strings
66    pub fn as_slice(&self) -> &[*const u8] {
67        unsafe {
68            core::slice::from_raw_parts(self.argv, self.argc)
69        }
70    }
71
72    ///Retrieves string by index.
73    ///
74    ///No checks, 100% unsafe.
75    pub unsafe fn get_str_by_index(&self, index: usize) -> &str {
76        let elem = *self.as_slice().get_unchecked(index);
77        crate::c_str_to_rust_unchecked(elem)
78    }
79}
80
81impl<'a> IntoIterator for &'a Args {
82    type Item = &'a str;
83    type IntoIter = IntoIter<'a>;
84
85    fn into_iter(self) -> Self::IntoIter {
86        Self::IntoIter {
87            inner: self,
88            index: 0,
89        }
90    }
91}
92
93///Iterator over [Args](struct.Args.html)
94///
95///Comparing to normal iterators can be iterated back and forth.
96pub struct IntoIter<'a> {
97    inner: &'a Args,
98    index: usize,
99}
100
101impl<'a> Iterator for IntoIter<'a> {
102    type Item = &'a str;
103
104    fn next(&mut self) -> Option<Self::Item> {
105        if self.index >= self.inner.argc {
106            return None;
107        }
108
109        let elem = unsafe { self.inner.get_str_by_index(self.index) };
110        self.index += 1;
111        Some(elem)
112    }
113
114    fn size_hint(&self) -> (usize, Option<usize>) {
115        let count = self.inner.argc - self.index;
116        (count, Some(count))
117    }
118
119    fn count(self) -> usize {
120        self.inner.argc - self.index
121    }
122}