1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! C style arguments wrapper

#[derive(Copy, Clone)]
///Wrapper over C-style arguments
///
///## Example:
///
///On most targets you can supply own C-style main function.
///
///One of the benefits is that it is no longer necessary to rely on allocating `std::env::Args`
///
///```rust
///#![no_main]
///
///#[no_mangle]
///unsafe extern "C" fn main(argc: isize, argv: *const *const u8) -> isize {
///    let args = c_ffi::Args::new(argc, argv).expect("To get function arguments");
///
///    0
///}
///```
pub struct Args {
    argc: usize,
    argv: *const *const u8,
}

impl Args {
    ///Creates new instance, but verifies that each string inside are UTF-8.
    ///
    ///On error returns pair: `(string index, Utf8Error)`
    ///
    ///The function is safe as long as you pass C style main function arguments.
    pub unsafe fn new(argc: isize, argv: *const *const u8) -> Result<Self, (usize, core::str::Utf8Error)> {
        debug_assert!(argc > 0);
        debug_assert!(!argv.is_null());

        let this = Args {
            argc: argc as usize,
            argv,
        };

        let args = this.as_slice();
        for idx in 0..this.argc {
            let arg = *args.get_unchecked(idx);
            if let Err(error) = crate::c_str_to_rust(arg) {
                return Err((idx, error));
            }
        }

        Ok(this)
    }

    #[inline(always)]
    ///Unchecked version of `Args::new`
    ///
    ///Do it on your own risk
    pub unsafe fn new_unchecked(argc: isize, argv: *const *const u8) -> Self {
        Args {
            argc: argc as usize,
            argv,
        }
    }

    #[inline(always)]
    ///Returns slice of raw C strings
    pub fn as_slice(&self) -> &[*const u8] {
        unsafe {
            core::slice::from_raw_parts(self.argv, self.argc)
        }
    }

    ///Retrieves string by index.
    ///
    ///No checks, 100% unsafe.
    pub unsafe fn get_str_by_index(&self, index: usize) -> &str {
        let elem = *self.as_slice().get_unchecked(index);
        crate::c_str_to_rust_unchecked(elem)
    }
}

impl<'a> IntoIterator for &'a Args {
    type Item = &'a str;
    type IntoIter = IntoIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        Self::IntoIter {
            inner: self,
            index: 0,
        }
    }
}

///Iterator over [Args](struct.Args.html)
///
///Comparing to normal iterators can be iterated back and forth.
pub struct IntoIter<'a> {
    inner: &'a Args,
    index: usize,
}

impl<'a> Iterator for IntoIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.inner.argc {
            return None;
        }

        let elem = unsafe { self.inner.get_str_by_index(self.index) };
        self.index += 1;
        Some(elem)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let count = self.inner.argc - self.index;
        (count, Some(count))
    }

    fn count(self) -> usize {
        self.inner.argc - self.index
    }
}