Files
ygglibc/src/error.rs
T

135 lines
3.0 KiB
Rust

use core::{
convert::Infallible,
ffi::c_int,
ops::{ControlFlow, FromResidual, Try},
};
use crate::header::{errno::Errno, stdio::EOF};
pub trait CZeroResult {
fn into_zero_status(self) -> c_int;
fn into_eof_status(self) -> c_int;
}
pub trait CSizeResult {
fn into_size_status(self) -> usize;
}
pub trait TryFromExt<T>: Sized {
fn e_try_from(value: T) -> EResult<Self>;
}
pub trait OptionExt<T> {
fn e_ok_or(self, err: yggdrasil_rt::Error) -> EResult<T>;
}
// TODO thread_local
#[no_mangle]
pub static mut errno: Errno = Errno(0);
pub enum EResult<T> {
Ok(T),
Err(yggdrasil_rt::Error),
Errno(Errno),
}
impl<T> From<Result<T, yggdrasil_rt::Error>> for EResult<T> {
fn from(value: Result<T, yggdrasil_rt::Error>) -> Self {
match value {
Ok(value) => Self::Ok(value),
Err(error) => Self::Err(error),
}
}
}
impl<T> EResult<T> {
pub fn into_set_errno(self) -> EResult<T> {
match self {
Self::Ok(value) => Self::Ok(value),
Self::Errno(e) => Self::Errno(e),
Self::Err(err) => {
let e = Errno::from(err);
unsafe {
errno = e;
}
Self::Errno(e)
}
}
}
}
impl CZeroResult for Result<(), Errno> {
fn into_zero_status(self) -> c_int {
match self {
Self::Ok(_) => 0,
Self::Err(_) => -1,
}
}
fn into_eof_status(self) -> c_int {
match self {
Self::Ok(_) => 0,
Self::Err(_) => EOF,
}
}
}
impl CSizeResult for Result<usize, Errno> {
fn into_size_status(self) -> usize {
match self {
Self::Ok(value) => value,
Self::Err(_) => 0,
}
}
}
impl<T> FromResidual<Errno> for EResult<T> {
fn from_residual(residual: Errno) -> Self {
Self::Errno(residual)
}
}
impl<T> FromResidual<yggdrasil_rt::Error> for EResult<T> {
fn from_residual(residual: yggdrasil_rt::Error) -> Self {
Self::Err(residual)
}
}
impl<T> FromResidual<Result<Infallible, Errno>> for EResult<T> {
fn from_residual(residual: Result<Infallible, Errno>) -> Self {
todo!()
}
}
impl<T> Try for EResult<T> {
type Output = T;
type Residual = Result<Infallible, Errno>;
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self.into_set_errno() {
Self::Ok(value) => ControlFlow::Continue(value),
Self::Errno(e) => ControlFlow::Break(Err(e)),
Self::Err(error) => unreachable!(),
}
}
fn from_output(output: Self::Output) -> Self {
todo!()
}
}
impl<T> OptionExt<T> for Option<T> {
fn e_ok_or(self, err: yggdrasil_rt::Error) -> EResult<T> {
match self {
Some(value) => EResult::Ok(value),
None => EResult::Err(err),
}
}
}
pub fn set_errno(e: Errno) {
unsafe {
errno = e;
}
}