2024-11-11 15:19:36 +02:00
|
|
|
use core::{
|
|
|
|
convert::Infallible,
|
|
|
|
ffi::c_int,
|
|
|
|
ops::{ControlFlow, FromResidual, Try},
|
|
|
|
ptr::{null_mut, NonNull},
|
|
|
|
};
|
|
|
|
|
|
|
|
use yggdrasil_rt::io::RawFd;
|
|
|
|
|
|
|
|
use crate::headers::{errno::Errno, sys_types::off_t};
|
|
|
|
|
|
|
|
macro impl_from_residual($($ty:ty),+) {
|
|
|
|
$(
|
|
|
|
impl FromResidual<EResult<Infallible>> for $ty {
|
|
|
|
fn from_residual(residual: EResult<Infallible>) -> Self {
|
|
|
|
let err = residual.unwrap_err();
|
|
|
|
unsafe {
|
|
|
|
errno = err;
|
|
|
|
}
|
|
|
|
Self::ERROR
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)+
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
pub static mut errno: Errno = Errno(0);
|
|
|
|
|
2024-11-12 11:01:39 +02:00
|
|
|
pub trait ResultExt<T, E> {
|
|
|
|
fn e_map_err<F: FnOnce(E) -> Errno>(self, map: F) -> EResult<T>;
|
|
|
|
}
|
|
|
|
|
2024-11-12 17:07:06 +02:00
|
|
|
pub trait OptionExt<T> {
|
|
|
|
fn e_ok_or(self, err: Errno) -> EResult<T>;
|
|
|
|
}
|
|
|
|
|
2024-11-11 15:19:36 +02:00
|
|
|
pub trait CResult {
|
|
|
|
const ERROR: Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[must_use = "EResult must be converted into its output type with proper errno set"]
|
|
|
|
pub enum EResult<T> {
|
|
|
|
Ok(T),
|
|
|
|
Err(Errno),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// On success: non-null ptr
|
|
|
|
/// On failure: NULL
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct CPtrResult<T>(*mut T);
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct CIsizeResult(isize);
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct CIntZeroResult(c_int);
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct CEofResult(c_int);
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct CIntCountResult(c_int);
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct CFdResult(c_int);
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
2024-11-12 11:01:39 +02:00
|
|
|
pub struct COffsetResult(pub(crate) off_t);
|
2024-11-11 15:19:36 +02:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct CUsizeResult(usize);
|
|
|
|
|
|
|
|
pub trait TryFromExt<T>: Sized {
|
|
|
|
fn e_try_from(value: T) -> EResult<Self>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> EResult<T> {
|
|
|
|
// pub fn is_ok(&self) -> bool {
|
|
|
|
// matches!(self, Self::Ok(_))
|
|
|
|
// }
|
|
|
|
|
|
|
|
pub fn is_err(&self) -> bool {
|
|
|
|
matches!(self, Self::Err(_))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ok(self) -> Option<T> {
|
|
|
|
match self {
|
|
|
|
Self::Ok(res) => Some(res),
|
|
|
|
Self::Err(_) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expect(self, message: &str) -> T {
|
|
|
|
match self {
|
|
|
|
Self::Ok(value) => value,
|
|
|
|
Self::Err(err) => panic!("expect() failed: {}, errno={:?}", message, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-12 12:19:56 +02:00
|
|
|
pub fn map<U, F: FnOnce(T) -> U>(self, map: F) -> EResult<U> {
|
|
|
|
match self {
|
|
|
|
Self::Ok(value) => EResult::Ok(map(value)),
|
|
|
|
Self::Err(err) => EResult::Err(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-11 15:19:36 +02:00
|
|
|
pub fn unwrap_err(self) -> Errno {
|
|
|
|
match self {
|
|
|
|
Self::Ok(_) => panic!("Expected an error"),
|
|
|
|
Self::Err(err) => err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn into_result<E, F: FnOnce(Errno) -> E>(
|
|
|
|
self,
|
|
|
|
map_err: F,
|
|
|
|
set_errno: bool,
|
|
|
|
) -> Result<T, E> {
|
|
|
|
match self {
|
|
|
|
Self::Ok(value) => Ok(value),
|
|
|
|
Self::Err(err) => {
|
|
|
|
if set_errno {
|
|
|
|
unsafe {
|
|
|
|
errno = err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(map_err(err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-12 11:01:39 +02:00
|
|
|
impl<T, E> ResultExt<T, E> for Result<T, E> {
|
|
|
|
fn e_map_err<F: FnOnce(E) -> Errno>(self, map: F) -> EResult<T> {
|
|
|
|
match self {
|
|
|
|
Ok(value) => EResult::Ok(value),
|
|
|
|
Err(value) => EResult::Err(map(value))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-12 17:07:06 +02:00
|
|
|
impl<T> OptionExt<T> for Option<T> {
|
|
|
|
fn e_ok_or(self, err: Errno) -> EResult<T> {
|
|
|
|
match self {
|
|
|
|
Some(value) => EResult::Ok(value),
|
|
|
|
None => EResult::Err(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-11 15:19:36 +02:00
|
|
|
impl<T> Try for EResult<T> {
|
|
|
|
type Output = T;
|
|
|
|
type Residual = EResult<Infallible>;
|
|
|
|
|
|
|
|
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
|
|
|
match self {
|
|
|
|
Self::Ok(value) => ControlFlow::Continue(value),
|
|
|
|
Self::Err(err) => ControlFlow::Break(EResult::Err(err)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from_output(output: Self::Output) -> Self {
|
|
|
|
Self::Ok(output)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> FromResidual<EResult<Infallible>> for EResult<T> {
|
|
|
|
fn from_residual(residual: EResult<Infallible>) -> Self {
|
|
|
|
let err = residual.unwrap_err();
|
|
|
|
Self::Err(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, E: Into<Errno>> FromResidual<Result<Infallible, E>> for EResult<T> {
|
|
|
|
fn from_residual(residual: Result<Infallible, E>) -> Self {
|
|
|
|
let err = residual.unwrap_err();
|
|
|
|
Self::Err(err.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, E: From<Errno>> FromResidual<EResult<Infallible>> for Result<T, E> {
|
|
|
|
fn from_residual(residual: EResult<Infallible>) -> Self {
|
|
|
|
let err = residual.unwrap_err();
|
|
|
|
Self::Err(err.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> CPtrResult<T> {
|
|
|
|
pub const fn success(ptr: NonNull<T>) -> Self {
|
|
|
|
Self(ptr.as_ptr())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> CResult for CPtrResult<T> {
|
|
|
|
const ERROR: Self = Self(null_mut());
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> FromResidual<EResult<Infallible>> for CPtrResult<T> {
|
|
|
|
fn from_residual(residual: EResult<Infallible>) -> Self {
|
|
|
|
let err = residual.unwrap_err();
|
|
|
|
unsafe {
|
|
|
|
errno = err;
|
|
|
|
}
|
|
|
|
Self::ERROR
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CIsizeResult {
|
|
|
|
pub const fn success(value: usize) -> Self {
|
|
|
|
Self(value as _)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CResult for CIsizeResult {
|
|
|
|
const ERROR: Self = Self(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CIntZeroResult {
|
|
|
|
pub const SUCCESS: Self = Self(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CResult for CIntZeroResult {
|
|
|
|
const ERROR: Self = Self(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CEofResult {
|
|
|
|
pub fn success(value: c_int) -> Self {
|
|
|
|
Self(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CResult for CEofResult {
|
|
|
|
const ERROR: Self = Self(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CIntCountResult {
|
|
|
|
pub fn success(value: c_int) -> Self {
|
|
|
|
Self(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CResult for CIntCountResult {
|
|
|
|
const ERROR: Self = Self(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CFdResult {
|
|
|
|
pub fn success(value: RawFd) -> Self {
|
|
|
|
Self(value.into_raw().try_into().unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CResult for CFdResult {
|
|
|
|
const ERROR: Self = Self(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl COffsetResult {
|
|
|
|
pub fn success(value: u64) -> Self {
|
|
|
|
Self(value.try_into().unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CResult for COffsetResult {
|
|
|
|
const ERROR: Self = Self(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CUsizeResult {
|
|
|
|
pub fn success(value: usize) -> Self {
|
|
|
|
Self(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CResult for CUsizeResult {
|
|
|
|
const ERROR: Self = Self(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_from_residual!(
|
|
|
|
CIsizeResult,
|
|
|
|
CIntZeroResult,
|
|
|
|
CEofResult,
|
|
|
|
CIntCountResult,
|
|
|
|
CFdResult,
|
|
|
|
COffsetResult,
|
|
|
|
CUsizeResult
|
|
|
|
);
|