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> for $ty { fn from_residual(residual: EResult) -> 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); pub trait ResultExt { fn e_map_err Errno>(self, map: F) -> EResult; } pub trait OptionExt { fn e_ok_or(self, err: Errno) -> EResult; } pub trait CResult { const ERROR: Self; } #[must_use = "EResult must be converted into its output type with proper errno set"] pub enum EResult { Ok(T), Err(Errno), } /// On success: non-null ptr /// On failure: NULL #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(transparent)] pub struct CPtrResult(*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)] pub struct COffsetResult(pub(crate) off_t); #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(transparent)] pub struct CUsizeResult(usize); pub trait TryFromExt: Sized { fn e_try_from(value: T) -> EResult; } impl EResult { // 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 { 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) } } pub fn map U>(self, map: F) -> EResult { match self { Self::Ok(value) => EResult::Ok(map(value)), Self::Err(err) => EResult::Err(err) } } pub fn unwrap_err(self) -> Errno { match self { Self::Ok(_) => panic!("Expected an error"), Self::Err(err) => err, } } pub fn into_result E>( self, map_err: F, set_errno: bool, ) -> Result { match self { Self::Ok(value) => Ok(value), Self::Err(err) => { if set_errno { unsafe { errno = err; } } Err(map_err(err)) } } } } impl ResultExt for Result { fn e_map_err Errno>(self, map: F) -> EResult { match self { Ok(value) => EResult::Ok(value), Err(value) => EResult::Err(map(value)) } } } impl OptionExt for Option { fn e_ok_or(self, err: Errno) -> EResult { match self { Some(value) => EResult::Ok(value), None => EResult::Err(err) } } } impl Try for EResult { type Output = T; type Residual = EResult; fn branch(self) -> ControlFlow { 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 FromResidual> for EResult { fn from_residual(residual: EResult) -> Self { let err = residual.unwrap_err(); Self::Err(err) } } impl> FromResidual> for EResult { fn from_residual(residual: Result) -> Self { let err = residual.unwrap_err(); Self::Err(err.into()) } } impl> FromResidual> for Result { fn from_residual(residual: EResult) -> Self { let err = residual.unwrap_err(); Self::Err(err.into()) } } impl CPtrResult { pub const fn success(ptr: NonNull) -> Self { Self(ptr.as_ptr()) } } impl CResult for CPtrResult { const ERROR: Self = Self(null_mut()); } impl FromResidual> for CPtrResult { fn from_residual(residual: EResult) -> 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 );