use lean_rs_sys::object::{lean_is_scalar, lean_unbox};
use crate::host::elaboration::LeanElabFailure;
use crate::host::evidence::handle::LeanEvidence;
use lean_rs::Obj;
use lean_rs::abi::structure::{ctor_tag, take_ctor_objects};
use lean_rs::abi::traits::{TryFromLean, conversion_error};
use lean_rs::error::LeanResult;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum EvidenceStatus {
Checked,
Rejected,
Unavailable,
Unsupported,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum LeanKernelOutcome<'lean> {
Checked(LeanEvidence<'lean>),
Rejected(LeanElabFailure),
Unavailable(LeanElabFailure),
Unsupported(LeanElabFailure),
}
impl LeanKernelOutcome<'_> {
#[must_use]
pub fn status(&self) -> EvidenceStatus {
match self {
Self::Checked(_) => EvidenceStatus::Checked,
Self::Rejected(_) => EvidenceStatus::Rejected,
Self::Unavailable(_) => EvidenceStatus::Unavailable,
Self::Unsupported(_) => EvidenceStatus::Unsupported,
}
}
}
impl<'lean> TryFromLean<'lean> for EvidenceStatus {
fn try_from_lean(obj: Obj<'lean>) -> LeanResult<Self> {
let raw = obj.as_raw_borrowed();
#[allow(unsafe_code)]
let tag = if unsafe { lean_is_scalar(raw) } {
#[allow(unsafe_code)]
let payload = unsafe { lean_unbox(raw) };
drop(obj);
payload
} else {
let heap_tag = ctor_tag(&obj)?;
let _ = take_ctor_objects::<0>(obj, heap_tag, "EvidenceStatus")?;
usize::from(heap_tag)
};
match tag {
0 => Ok(Self::Checked),
1 => Ok(Self::Rejected),
2 => Ok(Self::Unavailable),
3 => Ok(Self::Unsupported),
other => Err(conversion_error(format!(
"expected Lean EvidenceStatus tag 0..=3, found {other}"
))),
}
}
}
impl<'lean> TryFromLean<'lean> for LeanKernelOutcome<'lean> {
fn try_from_lean(obj: Obj<'lean>) -> LeanResult<Self> {
let tag = ctor_tag(&obj)?;
match tag {
0 => {
let [payload] = take_ctor_objects::<1>(obj, 0, "KernelOutcome.checked")?;
Ok(Self::Checked(LeanEvidence::try_from_lean(payload)?))
}
1 => {
let [payload] = take_ctor_objects::<1>(obj, 1, "KernelOutcome.rejected")?;
Ok(Self::Rejected(LeanElabFailure::try_from_lean(payload)?))
}
2 => {
let [payload] = take_ctor_objects::<1>(obj, 2, "KernelOutcome.unavailable")?;
Ok(Self::Unavailable(LeanElabFailure::try_from_lean(payload)?))
}
3 => {
let [payload] = take_ctor_objects::<1>(obj, 3, "KernelOutcome.unsupported")?;
Ok(Self::Unsupported(LeanElabFailure::try_from_lean(payload)?))
}
other => Err(conversion_error(format!(
"expected Lean KernelOutcome ctor (tag 0..=3), found tag {other}"
))),
}
}
}