//! System call argument validation functions
use libk::task::{mem::ForeignPointer, thread::Thread};
use yggdrasil_abi::error::Error;

/// Validates a &T passed as an address
pub fn ref_const<'a, T: Sized>(addr: usize) -> Result<&'a T, Error> {
    let proc = Thread::current();
    let ptr = addr as *const T;
    unsafe { ptr.validate_user_ptr(proc.address_space()) }
}
/// Validates a &mut T passed as an address
pub fn ref_mut<'a, T: Sized>(addr: usize) -> Result<&'a mut T, Error> {
    let proc = Thread::current();
    let ptr = addr as *mut T;
    unsafe { ptr.validate_user_mut(proc.address_space()) }
}

/// Validates a &str passed as base address and length
pub fn str_ref<'a>(base: usize, len: usize) -> Result<&'a str, Error> {
    if len == 0 {
        // Ignore the base
        return Ok("");
    }

    let slice = slice_ref(base, len)?;
    if slice.contains(&0) {
        log::warn!("User-supplied string contains NUL characters");
        return Err(Error::InvalidArgument);
    }
    Ok(core::str::from_utf8(slice).unwrap())
}

/// Validates a &[T] passed as base address and element count
pub fn slice_ref<'a, T: Sized>(base: usize, count: usize) -> Result<&'a [T], Error> {
    if count == 0 {
        // Ignore the base
        return Ok(&[]);
    }

    let proc = Thread::current();
    let ptr = base as *const T;
    unsafe { ptr.validate_user_slice(count, proc.address_space()) }
}
/// Validates a &mut [T] passed as base address and element count
pub fn slice_mut<'a, T: Sized>(base: usize, count: usize) -> Result<&'a mut [T], Error> {
    if count == 0 {
        // Ignore the base
        return Ok(&mut []);
    }

    let proc = Thread::current();
    let ptr = base as *mut T;
    unsafe { ptr.validate_user_slice_mut(count, proc.address_space()) }
}
