parent
e5c3f0deb0
commit
f79f186dc5
@ -0,0 +1,152 @@
|
|||||||
|
//! Error handling, reporting and propagating.
|
||||||
|
//!
|
||||||
|
//! Allows us to take advantage of `Result<T,E>` and interop idiomatic Rust error reporing with the ffi C functions' error reporting.
|
||||||
|
//! Functions returning or constructing `GHOST_TSuccess` will be able to be taken advantage of to be propagated and reported better.
|
||||||
|
//!
|
||||||
|
//! See [`GhostResult`] for more information.
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
error,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A result that returns potentially an error. In the form of `GHOST_TSuccess`.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
/// Its function is to provide more ergonomic error handling for Rust code, while still being able to easily interface with the C code.
|
||||||
|
/// # Propagating
|
||||||
|
/// Can be used to use `?` operator on functions returning `GHOST_TSuccess`.
|
||||||
|
///
|
||||||
|
/// When building on nightly, the following is possible.
|
||||||
|
/// ```
|
||||||
|
/// # use ghost::{error::GhostResult, c::GHOST_TSuccess};
|
||||||
|
/// extern "C" {fn returns_tsuccess() -> GHOST_TSuccess;}
|
||||||
|
///
|
||||||
|
/// fn try_things_internal() -> GHOST_TSuccess
|
||||||
|
/// {
|
||||||
|
/// unsafe {
|
||||||
|
/// returns_tsuccess()?;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// GHOST_TSuccess::Success
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn caller()
|
||||||
|
/// {
|
||||||
|
/// match try_things_internal() {
|
||||||
|
/// GHOST_TSuccess::Success => println!("Yay!"),
|
||||||
|
/// GHOST_TSuccess::Failure => panic!("Fug"),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// On stable, it must be rewritten a bit differently, however:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use ghost::{error::GhostResult, c::GHOST_TSuccess};
|
||||||
|
/// extern "C" {fn returns_tsuccess() -> GHOST_TSuccess;}
|
||||||
|
///
|
||||||
|
/// fn try_things_internal() -> GhostResult
|
||||||
|
/// {
|
||||||
|
/// unsafe {
|
||||||
|
/// returns_tsuccess()?;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn caller()
|
||||||
|
/// {
|
||||||
|
/// match try_things_internal() {
|
||||||
|
/// Ok(_) => println!("Yay!"),
|
||||||
|
/// Err(_) => panic!("Fug"),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// The bottom scenario is preferrable for Rust, as we are using `Result<T,E>` instead of an integer.
|
||||||
|
/// # When to use
|
||||||
|
/// This type should be preferred in Rust code, and `GHOST_TSuccess` preferred when doing a lot of FFI at once.
|
||||||
|
/// # Notes
|
||||||
|
/// *Usually* the internal result will be `()`. But idk if that will always be the case so it's still possible to set.
|
||||||
|
pub type GhostResult<T = ()> = Result<T, GhostError>;
|
||||||
|
|
||||||
|
/// Error type for failed GHOST calls.
|
||||||
|
/// As of yet it doesn't contain any information and is just an opaque zero-sized structure.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GhostError(());
|
||||||
|
impl error::Error for GhostError{}
|
||||||
|
impl fmt::Display for GhostError
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "GHOST function call failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<types::GHOST_TSuccess> for GhostResult
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: types::GHOST_TSuccess) -> Self
|
||||||
|
{
|
||||||
|
from.into_result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<GhostResult> for types::GHOST_TSuccess
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: GhostResult) -> Self
|
||||||
|
{
|
||||||
|
Self::from_result(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for types::GHOST_TSuccess
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Failure => write!(f, "Failure"),
|
||||||
|
Self::Success => write!(f, "Success"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(nightly)]
|
||||||
|
impl std::ops::Try for types::GHOST_TSuccess
|
||||||
|
{
|
||||||
|
type Ok = ();
|
||||||
|
type Error = GhostError;
|
||||||
|
|
||||||
|
fn into_result(self) -> Result<Self::Ok, Self::Error>
|
||||||
|
{
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
fn from_error(_: Self::Error) -> Self
|
||||||
|
{
|
||||||
|
Self::Failure
|
||||||
|
}
|
||||||
|
fn from_ok(_: Self::Ok) -> Self
|
||||||
|
{
|
||||||
|
Self::Success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl types::GHOST_TSuccess
|
||||||
|
{
|
||||||
|
/// Consume this instance into `Result<(), GhostError>`.
|
||||||
|
///
|
||||||
|
pub const fn into_result(self) -> GhostResult
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
types::GHOST_TSuccess::Success => Ok(()),
|
||||||
|
types::GHOST_TSuccess::Failure => Err(GhostError(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a `GhostResult` into `GHOST_TSuccess`.
|
||||||
|
pub const fn from_result(from: GhostResult) -> Self
|
||||||
|
{
|
||||||
|
match from {
|
||||||
|
Ok(_) => Self::Success,
|
||||||
|
Err(_) => Self::Failure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue