use crate::abi::structure::{alloc_ctor_with_objects, ctor_tag, take_ctor_objects};
use crate::abi::traits::{IntoLean, TryFromLean, conversion_error};
use crate::error::LeanResult;
use crate::runtime::LeanRuntime;
use crate::runtime::obj::Obj;
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) enum Except<E, T> {
Error(E),
Ok(T),
}
impl<E, T> From<Except<E, T>> for Result<T, E> {
fn from(value: Except<E, T>) -> Self {
match value {
Except::Ok(t) => Self::Ok(t),
Except::Error(e) => Self::Err(e),
}
}
}
impl<E, T> From<Result<T, E>> for Except<E, T> {
fn from(value: Result<T, E>) -> Self {
match value {
Ok(t) => Self::Ok(t),
Err(e) => Self::Error(e),
}
}
}
impl<'lean, E, T> IntoLean<'lean> for Except<E, T>
where
E: IntoLean<'lean>,
T: IntoLean<'lean>,
{
fn into_lean(self, runtime: &'lean LeanRuntime) -> Obj<'lean> {
match self {
Self::Error(e) => alloc_ctor_with_objects(runtime, 0, [e.into_lean(runtime)]),
Self::Ok(t) => alloc_ctor_with_objects(runtime, 1, [t.into_lean(runtime)]),
}
}
}
impl<'lean, E, T> TryFromLean<'lean> for Except<E, T>
where
E: TryFromLean<'lean>,
T: TryFromLean<'lean>,
{
fn try_from_lean(obj: Obj<'lean>) -> LeanResult<Self> {
let tag = ctor_tag(&obj)?;
match tag {
0 => {
let [field] = take_ctor_objects::<1>(obj, 0, "Except::error")?;
Ok(Self::Error(E::try_from_lean(field)?))
}
1 => {
let [field] = take_ctor_objects::<1>(obj, 1, "Except::ok")?;
Ok(Self::Ok(T::try_from_lean(field)?))
}
other => Err(conversion_error(format!(
"expected Lean Except ctor (tag 0 = error, 1 = ok), found tag {other}"
))),
}
}
}
impl<'lean, T, E> IntoLean<'lean> for Result<T, E>
where
E: IntoLean<'lean>,
T: IntoLean<'lean>,
{
fn into_lean(self, runtime: &'lean LeanRuntime) -> Obj<'lean> {
Except::<E, T>::from(self).into_lean(runtime)
}
}
impl<'lean, T, E> TryFromLean<'lean> for Result<T, E>
where
E: TryFromLean<'lean>,
T: TryFromLean<'lean>,
{
fn try_from_lean(obj: Obj<'lean>) -> LeanResult<Self> {
Except::<E, T>::try_from_lean(obj).map(Self::from)
}
}
#[allow(unsafe_code, reason = "LeanAbi::from_c wraps an owned `lean_obj_res` pointer")]
mod lean_abi_impls {
use super::{Except, IntoLean, LeanResult, LeanRuntime, Obj, TryFromLean};
impl<E, T> crate::abi::traits::sealed::SealedAbi for Except<E, T> {}
impl<'lean, E, T> crate::abi::traits::LeanAbi<'lean> for Except<E, T>
where
E: IntoLean<'lean> + TryFromLean<'lean>,
T: IntoLean<'lean> + TryFromLean<'lean>,
{
type CRepr = *mut lean_rs_sys::lean_object;
fn into_c(self, runtime: &'lean LeanRuntime) -> Self::CRepr {
self.into_lean(runtime).into_raw()
}
#[allow(
clippy::not_unsafe_ptr_arg_deref,
reason = "sealed trait — caller invariant documented on LeanAbi::from_c"
)]
fn from_c(c: Self::CRepr, runtime: &'lean LeanRuntime) -> LeanResult<Self> {
let obj = unsafe { Obj::from_owned_raw(runtime, c) };
Self::try_from_lean(obj)
}
}
impl<T, E> crate::abi::traits::sealed::SealedAbi for Result<T, E> {}
impl<'lean, T, E> crate::abi::traits::LeanAbi<'lean> for Result<T, E>
where
T: IntoLean<'lean> + TryFromLean<'lean>,
E: IntoLean<'lean> + TryFromLean<'lean>,
{
type CRepr = *mut lean_rs_sys::lean_object;
fn into_c(self, runtime: &'lean LeanRuntime) -> Self::CRepr {
self.into_lean(runtime).into_raw()
}
#[allow(
clippy::not_unsafe_ptr_arg_deref,
reason = "sealed trait — caller invariant documented on LeanAbi::from_c"
)]
fn from_c(c: Self::CRepr, runtime: &'lean LeanRuntime) -> LeanResult<Self> {
let obj = unsafe { Obj::from_owned_raw(runtime, c) };
Self::try_from_lean(obj)
}
}
}