use crate::OsStr;
pub(crate) fn args_os_ref_iter() -> IterArgsOsRef {
IterArgsOsRef { platform_specific: r#impl::args_os_ref_iter() }
}
#[doc = crate::_tags!(iterator lifetime)]
#[doc = crate::_doc_miri_warn!(tag)]
#[doc = crate::_doc_location!("sys/env")]
#[doc = crate::_doc!(vendor: "argv")]
#[derive(Debug)]
pub struct IterArgsOsRef {
platform_specific: r#impl::IterArgsOsRef,
}
impl Iterator for IterArgsOsRef {
type Item = &'static OsStr;
fn next(&mut self) -> Option<Self::Item> {
self.platform_specific.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.platform_specific.size_hint()
}
}
impl ExactSizeIterator for IterArgsOsRef {
fn len(&self) -> usize {
self.platform_specific.len()
}
}
#[cfg(all(target_os = "linux", not(target_env = "musl"), not(miri)))]
mod r#impl {
use crate::{CStr, OsStr, c_char, c_int};
use std::os::unix::ffi::OsStrExt;
use std::{mem, ptr};
static mut ARGC: c_int = 0;
static mut ARGV: *const *const c_char = ptr::null();
#[cfg(target_os = "linux")]
#[unsafe(link_section = ".init_array")]
#[used]
static CAPTURE: unsafe extern "C" fn(c_int, *const *const c_char) = capture;
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
#[allow(dead_code)]
unsafe extern "C" fn capture(argc: c_int, argv: *const *const c_char) {
unsafe {
ARGC = argc;
ARGV = argv;
}
}
pub(crate) fn args_os_ref_iter() -> IterArgsOsRef {
let argc = unsafe { ARGC };
let argv = unsafe { ARGV };
let end = unsafe { argv.offset(argc as isize) };
IterArgsOsRef { next: argv, end }
}
#[derive(Debug)]
pub(crate) struct IterArgsOsRef {
next: *const *const c_char,
end: *const *const c_char,
}
impl Iterator for IterArgsOsRef {
type Item = &'static OsStr;
fn next(&mut self) -> Option<Self::Item> {
if ptr::eq(self.next, self.end) {
None
} else {
let ptr = unsafe { *self.next };
let c_str = unsafe { CStr::from_ptr(ptr) };
self.next = unsafe { self.next.offset(1) };
Some(OsStr::from_bytes(c_str.to_bytes()))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl ExactSizeIterator for IterArgsOsRef {
fn len(&self) -> usize {
(self.end as usize - self.next as usize) / mem::size_of::<*const c_char>()
}
}
unsafe impl Send for IterArgsOsRef {}
unsafe impl Sync for IterArgsOsRef {}
}
#[cfg(any(not(target_os = "linux"), target_env = "musl", miri))]
mod r#impl {
use crate::{Once, OsStr};
use std::{env, iter, ptr, slice};
static ONCE: Once = Once::new();
static mut ARGV: Vec<&'static OsStr> = Vec::new();
pub(crate) fn args_os_ref_iter() -> IterArgsOsRef {
ONCE.call_once(|| {
let argv = env::args_os()
.map(|arg| -> &OsStr { Box::leak(arg.into_boxed_os_str()) })
.collect();
unsafe { ARGV = argv }
});
let argv = unsafe { &*ptr::addr_of!(ARGV) };
argv.iter().copied()
}
pub(crate) type IterArgsOsRef = iter::Copied<slice::Iter<'static, &'static OsStr>>;
}
const _AUTO_TRAITS: () = {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
let _ = assert_send::<IterArgsOsRef>;
let _ = assert_sync::<IterArgsOsRef>;
};