use core::{
ffi::{c_char, c_int, CStr},
ptr::null,
};
pub struct StaticArgs {
next: *const *const c_char,
end: *const *const c_char,
}
impl StaticArgs {
pub const fn empty() -> Self {
Self {
next: null(),
end: null(),
}
}
pub const unsafe fn new(argc: c_int, argv: *const *const c_char) -> Self {
Self {
next: argv,
end: argv.offset(argc as isize),
}
}
}
impl Iterator for StaticArgs {
type Item = &'static CStr;
fn next(&mut self) -> Option<Self::Item> {
if self.next == self.end {
None
} else {
let c_str = unsafe { CStr::from_ptr(*self.next) };
self.next = unsafe { self.next.offset(1) };
Some(c_str)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
#[rustversion::nightly]
impl ExactSizeIterator for StaticArgs {
fn len(&self) -> usize {
unsafe {
(self.end as usize).unchecked_sub(self.next as usize)
}
}
}
#[rustversion::not(nightly)]
impl ExactSizeIterator for StaticArgs {
fn len(&self) -> usize {
self.end as usize - self.next as usize
}
}
static mut ARGC: c_int = 0;
static mut ARGV: *const *const c_char = null();
#[cfg(any(
all(target_os = "linux", target_env = "gnu"),
target_os = "macos",
target_os = "android",
target_os = "freebsd",
feature = "unsafe_impl"
))]
#[cfg_attr(
any(
all(target_os = "linux", target_env = "gnu"),
target_os = "freebsd",
target_os = "android",
feature = "unsafe_impl"
),
link_section = ".init_array"
)]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
#[used]
static ARGV_INIT_ARRAY: extern "C" fn(c_int, *const *const c_char, *const *const c_char) = {
extern "C" fn init_wrapper(
argc: c_int,
argv: *const *const c_char,
_envp: *const *const c_char,
) {
unsafe {
ARGC = argc;
ARGV = argv;
}
}
init_wrapper
};
#[must_use = "Iterators do nothing unless consumed"]
pub fn static_args() -> StaticArgs {
if unsafe { ARGV.is_null() } {
StaticArgs::empty()
} else {
unsafe { StaticArgs::new(ARGC, ARGV) }
}
}