Files
ygglibc/src/util.rs
T

80 lines
1.8 KiB
Rust

use core::marker::PhantomData;
use yggdrasil_rt::path::Path;
use crate::{
error::{EResult, OptionExt},
path::{PathBuf, PathExt},
ENVS,
};
pub trait Nullable {
fn is_null(&self) -> bool;
}
pub struct NullTerminated<'a, T: Nullable> {
data: *const T,
_pd: PhantomData<&'a ()>,
}
impl<T> Nullable for *const T {
fn is_null(&self) -> bool {
<*const T>::is_null(*self)
}
}
impl<T> Nullable for *mut T {
fn is_null(&self) -> bool {
<*mut T>::is_null(*self)
}
}
impl<'a, T: Nullable> NullTerminated<'a, T> {
pub unsafe fn try_from_ptr(ptr: *const T) -> Option<Self> {
(!ptr.is_null()).then(|| Self {
data: ptr,
_pd: PhantomData,
})
}
}
impl<'a, T: Nullable + 'a> Iterator for NullTerminated<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let value = unsafe { &*self.data };
if value.is_null() {
return None;
}
self.data = unsafe { self.data.add(1) };
Some(value)
}
}
pub fn envs() -> impl Iterator<Item = (&'static str, &'static str)> {
// SAFETY C_ENVS is only mutable during init
let it = unsafe { ENVS.iter() };
it.filter_map(|v| v.to_str().ok().and_then(|s| s.split_once('=')))
}
pub fn getenv(name: &str) -> Option<&'static str> {
envs().find_map(|(k, v)| (k == name).then_some(v))
}
pub fn resolve_binary<P: AsRef<Path>>(name: P) -> EResult<PathBuf> {
let name = name.as_ref();
if name.is_absolute() {
return EResult::Ok(PathBuf::from(name));
}
let env_path = getenv("PATH").e_ok_or(yggdrasil_rt::Error::DoesNotExist)?;
for el in env_path.split(':') {
let path = PathBuf::from_str(el).join(name);
if path.exists() {
return EResult::Ok(path);
}
}
EResult::Err(yggdrasil_rt::Error::DoesNotExist)
}