#![allow(clippy::while_let_on_iterator, unused_qualifications)]
import! {
{
iter::{Iterator, FusedIterator},
ops::{Fn, FnMut},
option::Option::{self, None, Some}
}
}
#[cfg(feature = "rev_iter")]
import! {
iter::DoubleEndedIterator
}
use {
super::{args::Args, helpers::len},
cmdline::helpers,
direct
};
macro_rules! fallible_q {
($self:ident, $f:expr, $i:expr) => {
#[cfg(not(feature = "infallible_map"))]
$f
#[cfg(feature = "infallible_map")]
if $self.fallible {
$f
} else {
$i
}
};
}
macro_rules! next_back {
($self:ident) => {{
while $self.cur != $self.end {
$self.end = unsafe { $self.end.sub(1) };
assume!(!$self.end.is_null() && $self.end > $self.cur);
if let Some(v) = ($self.map)(unsafe { $self.end.read() }) {
return Some(v);
}
}
None
}};
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct MappedArgs<Ret, F: Fn(*const u8) -> Option<Ret> = fn(*const u8) -> Option<Ret>> {
pub(crate) cur: *const *const u8,
pub(crate) end: *const *const u8,
pub(crate) map: F,
#[cfg(feature = "infallible_map")]
pub(crate) fallible: bool
}
impl MappedArgs<&'static str, fn(*const u8) -> Option<&'static str>> {
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn utf8() -> MappedArgs<&'static str, fn(*const u8) -> Option<&'static str>> {
MappedArgs::new(helpers::try_to_str)
}
}
#[cfg(feature = "std")]
impl MappedArgs<&'static ::std::ffi::OsStr, fn(*const u8) -> Option<&'static ::std::ffi::OsStr>> {
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn osstr()
-> MappedArgs<&'static ::std::ffi::OsStr, fn(*const u8) -> Option<&'static ::std::ffi::OsStr>>
{
#[cfg(not(feature = "infallible_map"))]
{
MappedArgs::new(helpers::to_osstr)
}
#[cfg(feature = "infallible_map")]
{
unsafe { MappedArgs::new_infallible(helpers::to_osstr) }
}
}
}
#[allow(clippy::len_without_is_empty)]
impl<Ret, F: Fn(*const u8) -> Option<Ret>> MappedArgs<Ret, F> {
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn new(map: F) -> MappedArgs<Ret, F> {
let (argc, argv) = direct::argc_argv();
MappedArgs {
cur: argv,
end: helpers::back(argv, argc),
map,
#[cfg(feature = "infallible_map")]
fallible: true
}
}
#[cfg(feature = "infallible_map")]
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub unsafe fn new_infallible(map: F) -> MappedArgs<Ret, F> {
let (argc, argv) = direct::argc_argv();
MappedArgs { cur: argv, end: helpers::back(argv, argc), map, fallible: false }
}
#[must_use]
#[cfg_attr(not(feature = "no_cold"), cold)]
pub fn unmap(self) -> Args {
Args { cur: self.cur, end: self.end }
}
pub fn len(&self) -> Option<usize> {
#[cfg(not(feature = "infallible_map"))]
{
None
}
#[cfg(feature = "infallible_map")]
{
if self.fallible { None } else { Some(unsafe { len(self.cur, self.end) }) }
}
}
}
impl<Ret, F: Fn(*const u8) -> Option<Ret>> Iterator for MappedArgs<Ret, F> {
type Item = Ret;
#[allow(clippy::inline_always)]
#[inline(always)]
fn next(&mut self) -> Option<Ret> {
while self.cur != self.end {
let p = self.cur;
self.cur = unsafe { self.cur.add(1) };
assume!(!p.is_null() && p < self.end);
if let Some(v) = (self.map)(unsafe { p.read() }) {
return Some(v);
}
}
None
}
#[allow(clippy::inline_always)]
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
#[cfg(not(feature = "infallible_map"))]
{
(0, Some(unsafe { len(self.cur, self.end) }))
}
#[cfg(feature = "infallible_map")]
{
let len = unsafe { len(self.cur, self.end) };
if self.fallible { (0, Some(len)) } else { (len, Some(len)) }
}
}
#[cfg(feature = "infallible_map")]
#[inline]
fn count(self) -> usize {
if self.fallible {
self.fold(0, |count, _| count + 1)
} else {
unsafe { len(self.cur, self.end) }
}
}
#[inline]
fn last(mut self) -> Option<Ret> {
#[cfg(feature = "rev_iter")]
{
self.next_back()
}
#[cfg(not(feature = "rev_iter"))]
{
next_back!(self)
}
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Ret> {
if n >= unsafe { len(self.cur, self.end) } {
self.cur = self.end;
return None;
}
fallible_q!(
self,
{
let mut i = 0;
while self.cur != self.end {
let p = self.cur;
self.cur = unsafe { self.cur.add(1) };
assume!(!p.is_null() && p < self.end);
if let Some(v) = (self.map)(unsafe { p.read() }) {
if i == n {
return Some(v);
}
i += 1;
}
}
},
{
self.cur = unsafe { self.cur.add(n) };
assume!(!self.cur.is_null() && self.cur < self.end);
return self.next();
}
);
None
}
#[inline]
fn fold<B, G: FnMut(B, Ret) -> B>(mut self, mut acc: B, mut f: G) -> B {
if self.cur == self.end {
return acc;
}
loop {
assume!(!self.cur.is_null() && self.cur < self.end);
fallible_q!(
self,
{
if let Some(v) = (self.map)(unsafe { self.cur.read() }) {
acc = f(acc, v);
}
},
{
acc = f(
acc,
assume!(
car,
Some,
e,
unsafe { (self.map)(self.cur.read()) },
"map is infallible, but returned None"
)
);
}
);
self.cur = unsafe { self.cur.add(1) };
if self.cur == self.end {
break;
}
}
acc
}
}
#[cfg(feature = "rev_iter")]
impl<Ret, F: Fn(*const u8) -> Option<Ret>> DoubleEndedIterator for MappedArgs<Ret, F> {
#[inline]
fn next_back(&mut self) -> Option<Ret> {
next_back!(self)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Ret> {
if n >= unsafe { len(self.cur, self.end) } {
self.cur = self.end;
return None;
}
fallible_q!(
self,
{
let mut i = 0;
while self.cur != self.end {
self.end = unsafe { self.end.sub(1) };
assume!(!self.end.is_null() && self.end > self.cur);
if let Some(v) = (self.map)(unsafe { self.end.read() }) {
if i == n {
return Some(v);
}
i += 1;
}
}
},
{
self.end = unsafe { self.end.sub(n) };
assume!(!self.end.is_null() && self.end > self.cur);
return self.next_back();
}
);
None
}
#[inline]
fn rfold<B, G: FnMut(B, Ret) -> B>(mut self, mut acc: B, mut f: G) -> 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);
#[cfg(not(feature = "infallible_map"))]
{
if let Some(v) = (self.map)(unsafe { self.end.read() }) {
acc = f(acc, v);
}
}
#[cfg(feature = "infallible_map")]
{
if self.fallible {
if let Some(v) = (self.map)(unsafe { self.end.read() }) {
acc = f(acc, v);
}
} else {
acc = f(
acc,
assume!(
car,
Some,
e,
unsafe { (self.map)(self.end.read()) },
"map is infallible, but returned None"
)
);
}
}
if self.cur == self.end {
break;
}
}
acc
}
}
impl<Ret, F: Fn(*const u8) -> Option<Ret>> FusedIterator for MappedArgs<Ret, F> {}