294 lines
6.4 KiB
Rust
Raw Normal View History

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);
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)]
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)
}
}
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))
}
}
}
}
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
);