use crate::inventory::{Inventory, TypeId};
use crate::lang::meta::{Visibility, common_or_module_emission};
use crate::lang::types::{Type, TypeInfo, TypeKind, TypePattern, WireIO};
use crate::wire::SerializationError;
use std::any::Any;
use std::fmt::Debug;
use std::io::{Read, Write};
use std::panic::{AssertUnwindSafe, catch_unwind};
pub fn get_panic_message(pan: &(dyn Any + Send)) -> &str {
match pan.downcast_ref::<&'static str>() {
Some(s) => s,
None => match pan.downcast_ref::<String>() {
Some(s) => s,
None => "Any { .. }",
},
}
}
#[repr(u32)]
#[derive(Debug, Clone)]
#[must_use]
pub enum Result<T, E> {
Ok(T),
Err(E),
Panic,
Null,
}
impl<T, E> ResultAs for Result<T, E> {
type AsT<X> = Result<X, E>;
}
impl<T, E> Result<T, E> {
#[must_use]
pub fn is_ok(&self) -> bool {
matches!(self, Self::Ok(_))
}
pub fn unwrap(self) -> T {
if let Self::Ok(t) = self {
t
} else {
panic!("Called `unwrap` on an `FFIResult` that is not `Ok`.")
}
}
pub fn unwrap_err(self) -> E {
if let Self::Err(err) = self {
err
} else {
panic!("Called `unwrap_err` on an `FFIResult` that is not `Err`.")
}
}
}
impl<T, E> From<std::result::Result<T, E>> for Result<T, E>
where
T: TypeInfo,
E: TypeInfo,
{
fn from(x: std::result::Result<T, E>) -> Self {
match x {
Ok(t) => Self::Ok(t),
Err(err) => Self::Err(err),
}
}
}
unsafe impl<T: TypeInfo, E: TypeInfo> TypeInfo for Result<T, E> {
const WIRE_SAFE: bool = T::WIRE_SAFE && E::WIRE_SAFE;
const RAW_SAFE: bool = T::RAW_SAFE && E::RAW_SAFE;
const ASYNC_SAFE: bool = T::ASYNC_SAFE && E::ASYNC_SAFE;
const SERVICE_SAFE: bool = false;
const SERVICE_CTOR_SAFE: bool = T::SERVICE_SAFE;
fn id() -> TypeId {
TypeId::new(0x9BCBD2325F73A8CBDAE991B5BB8EB6FC).derive_id(T::id()).derive_id(E::id())
}
fn kind() -> TypeKind {
TypeKind::TypePattern(TypePattern::Result(T::id(), E::id()))
}
fn ty() -> Type {
let t = T::ty();
let e = E::ty();
Type {
emission: common_or_module_emission(&[t.emission, e.emission]),
docs: crate::lang::meta::Docs::empty(),
visibility: Visibility::Public,
name: format!("Result<{}, {}>", t.name, e.name),
kind: Self::kind(),
}
}
fn register(inventory: &mut impl Inventory) {
T::register(inventory);
E::register(inventory);
inventory.register_type(Self::id(), Self::ty());
}
}
unsafe impl<T: WireIO, E: WireIO> WireIO for Result<T, E> {
fn write(&self, _: &mut impl Write) -> std::result::Result<(), SerializationError> {
todo!()
}
fn read(_: &mut impl Read) -> std::result::Result<Self, SerializationError> {
todo!()
}
fn live_size(&self) -> usize {
todo!()
}
}
pub fn result_to_ffi<T: TypeInfo, E: TypeInfo>(f: impl FnOnce() -> std::result::Result<T, E>) -> Result<T, E> {
f().into()
}
pub async fn result_to_ffi_async<T: TypeInfo, E: TypeInfo>(f: impl std::ops::AsyncFnOnce() -> std::result::Result<T, E>) -> Result<T, E> {
f().await.into()
}
pub fn panic_to_result<T: TypeInfo, E: TypeInfo>(f: impl FnOnce() -> Result<T, E>) -> Result<T, E> {
catch_unwind(AssertUnwindSafe(f)).unwrap_or_else(|_| Result::Panic)
}
#[doc(hidden)]
pub trait ResultAs {
type AsT<T>;
}