use core::str::Utf8Error;
use crate::error::Error;
use rusl::string::strlen::strlen;
use rusl::string::unix_str::UnixStr;
pub(crate) static mut ENV: Env = Env {
arg_c: 0,
arg_v: core::ptr::null(),
env_p: core::ptr::null(),
};
#[expect(clippy::struct_field_names)]
pub(crate) struct Env {
pub(crate) arg_c: u64,
pub(crate) arg_v: *const *const u8,
pub(crate) env_p: *const *const u8,
}
#[derive(Debug, Copy, Clone)]
pub enum VarError {
Missing,
NotUnicode(Utf8Error),
}
pub fn var_unix(key: &UnixStr) -> Result<&'static UnixStr, VarError> {
let mut env_ptr = unsafe { ENV.env_p };
while !env_ptr.is_null() {
unsafe {
let var_ptr = env_ptr.read();
if var_ptr.is_null() {
return Err(VarError::Missing);
}
let match_up_to = key.match_up_to(UnixStr::from_ptr(var_ptr));
if match_up_to != 0 {
if var_ptr.add(match_up_to).read() == b'=' {
return Ok(UnixStr::from_ptr(var_ptr.add(match_up_to + 1)));
}
}
env_ptr = env_ptr.add(1);
}
}
Err(VarError::Missing)
}
pub fn var(key: &str) -> Result<&'static str, VarError> {
let mut env_ptr = unsafe { ENV.env_p };
while !env_ptr.is_null() {
unsafe {
let var_ptr = env_ptr.read();
if var_ptr.is_null() {
return Err(VarError::Missing);
}
let match_up_to = UnixStr::from_ptr(var_ptr).match_up_to_str(key);
if match_up_to != 0 {
if var_ptr.add(match_up_to).read() == b'=' {
let value_len = strlen(var_ptr.add(match_up_to + 1));
let value_slice =
core::slice::from_raw_parts(var_ptr.add(match_up_to + 1), value_len);
return core::str::from_utf8(value_slice).map_err(VarError::NotUnicode);
}
}
env_ptr = env_ptr.add(1);
}
}
Err(VarError::Missing)
}
#[inline]
#[must_use]
pub fn args() -> Args {
Args(args_os())
}
#[inline]
#[must_use]
#[expect(clippy::cast_possible_truncation)]
pub fn args_os() -> ArgsOs {
ArgsOs {
ind: 0,
num_args: unsafe { ENV.arg_c } as usize,
}
}
pub struct Args(ArgsOs);
impl Iterator for Args {
type Item = Result<&'static str, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|e| Ok(UnixStr::as_str(e)?))
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.0.num_args
}
}
pub struct ArgsOs {
ind: usize,
num_args: usize,
}
impl Iterator for ArgsOs {
type Item = &'static UnixStr;
fn next(&mut self) -> Option<Self::Item> {
if self.ind < self.num_args {
unsafe {
let arg_ptr = ENV.arg_v.add(self.ind);
self.ind += 1;
if arg_ptr.is_null() {
return None;
}
let arg = arg_ptr.read();
if arg.is_null() {
return None;
}
return Some(UnixStr::from_ptr(arg));
}
}
None
}
}
impl ExactSizeIterator for ArgsOs {
fn len(&self) -> usize {
self.num_args
}
}