#![allow(clippy::while_let_on_iterator)]
import! {
{
default::Default,
iter::{ExactSizeIterator, FusedIterator, Iterator},
ops::{Fn, FnMut},
option::Option::{self, None, Some},
}
}
#[cfg(feature = "rev_iter")]
import! {
iter::DoubleEndedIterator
}
use {
crate::{CStr, MappedArgs, cmdline::helpers::try_to_str, iter::helpers::len},
cmdline::helpers,
direct
};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Args {
pub(crate) cur: *const *const u8,
pub(crate) end: *const *const u8
}
impl Default for Args {
fn default() -> Self {
Self::new()
}
}
impl Args {
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn new() -> Args {
let (argc, argv) = direct::argc_argv();
Args { cur: argv, end: helpers::back(argv, argc) }
}
#[must_use]
pub fn as_slice(&self) -> &'static [CStr<'static>] {
unsafe {
switch!(core::slice::from_raw_parts(
self.cur.cast::<CStr<'static>>(),
len(self.cur, self.end)
))
}
}
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn map_ty<Ret, F: Fn(*const u8) -> Option<Ret>>(&self, map: F) -> MappedArgs<Ret, F> {
MappedArgs {
cur: self.cur,
end: self.end,
map,
#[cfg(feature = "infallible_map")]
fallible: true
}
}
#[cfg(feature = "infallible_map")]
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn map_ty_infallible<Ret, F: Fn(*const u8) -> Option<Ret>>(
&self,
map: F
) -> MappedArgs<Ret, F> {
MappedArgs { cur: self.cur, end: self.end, map, fallible: false }
}
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn map_str(&self) -> MappedArgs<&'static str, fn(*const u8) -> Option<&'static str>> {
MappedArgs {
cur: self.cur,
end: self.end,
map: try_to_str,
#[cfg(all(feature = "infallible_map", not(feature = "assume_valid_str")))]
fallible: true,
#[cfg(all(feature = "infallible_map", feature = "assume_valid_str"))]
fallible: false
}
}
#[cfg(feature = "std")]
#[must_use]
#[allow(unused_qualifications)]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn map_os(
&self
) -> MappedArgs<&'static ::std::ffi::OsStr, fn(*const u8) -> Option<&'static ::std::ffi::OsStr>>
{
MappedArgs {
cur: self.cur,
end: self.end,
map: helpers::to_osstr,
#[cfg(feature = "infallible_map")]
fallible: false
}
}
#[allow(clippy::inline_always)]
#[inline(always)]
unsafe fn next_back_unchecked(&mut self) -> CStr<'static> {
self.end = self.end.sub(1);
assume!(!self.end.is_null() && self.end > self.cur);
CStr::from_ptr(self.end.read())
}
#[allow(clippy::inline_always)]
#[inline(always)]
unsafe fn next_unchecked(&mut self) -> CStr<'static> {
let p = self.cur;
self.cur = self.cur.add(1);
assume!(!p.is_null() && p < self.end);
CStr::from_ptr(p.read())
}
}
impl Iterator for Args {
type Item = CStr<'static>;
#[allow(clippy::inline_always)]
#[inline(always)]
fn next(&mut self) -> Option<CStr<'static>> {
if self.cur == self.end {
return None;
}
assume!(self.cur < self.end);
Some(unsafe { self.next_unchecked() })
}
#[allow(clippy::inline_always)]
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = unsafe { len(self.cur, self.end) };
(len, Some(len))
}
#[inline]
fn count(self) -> usize {
self.len()
}
#[inline]
fn last(mut self) -> Option<CStr<'static>> {
#[cfg(feature = "rev_iter")]
{
self.next_back()
}
#[cfg(not(feature = "rev_iter"))]
{
if self.cur == self.end {
return None;
}
Some(unsafe { self.next_back_unchecked() })
}
}
#[inline]
fn nth(&mut self, n: usize) -> Option<CStr<'static>> {
if n >= self.len() {
self.cur = self.end;
return None;
}
self.cur = unsafe { self.cur.add(n) };
assume!(self.cur < self.end);
Some(unsafe { self.next_unchecked() })
}
#[inline]
fn fold<B, F: FnMut(B, CStr<'static>) -> B>(mut self, mut acc: B, mut f: F) -> B {
if self.cur == self.end {
return acc;
}
loop {
assume!(!self.cur.is_null() && self.cur < self.end);
acc = f(acc, unsafe { CStr::from_ptr(self.cur.read()) });
self.cur = unsafe { self.cur.add(1) };
if self.cur == self.end {
break;
}
}
acc
}
}
#[cfg(feature = "rev_iter")]
impl DoubleEndedIterator for Args {
#[inline]
fn next_back(&mut self) -> Option<CStr<'static>> {
if self.cur == self.end {
return None;
}
Some(unsafe { self.next_back_unchecked() })
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<CStr<'static>> {
if n >= self.len() {
self.end = self.cur;
return None;
}
self.end = unsafe { self.end.sub(n) };
assume!(!self.end.is_null() && self.end > self.cur);
Some(unsafe { self.next_back_unchecked() })
}
#[inline]
fn rfold<B, F: FnMut(B, CStr<'static>) -> B>(mut self, mut acc: B, mut f: F) -> B {
if self.cur == self.end {
return acc;
}
loop {
self.end = unsafe { self.end.sub(1) };
assume!(!self.end.is_null() && self.end > self.cur);
acc = f(acc, unsafe { CStr::from_ptr(self.end.read()) });
if self.cur == self.end {
break;
}
}
acc
}
}
impl ExactSizeIterator for Args {
#[allow(clippy::inline_always)]
#[inline(always)]
fn len(&self) -> usize {
unsafe { len(self.cur, self.end) }
}
}
impl FusedIterator for Args {}