use crate::host::elaboration::LeanElabFailure;
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::{LeanDiagnosticCode, LeanResult};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum MetaCallStatus {
Ok,
Failed,
TimeoutOrHeartbeat,
Unsupported,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum LeanMetaResponse<Resp> {
Ok(Resp),
Failed(LeanElabFailure),
TimeoutOrHeartbeat(LeanElabFailure),
Unsupported(LeanElabFailure),
}
impl<Resp> LeanMetaResponse<Resp> {
#[must_use]
pub fn status(&self) -> MetaCallStatus {
match self {
Self::Ok(_) => MetaCallStatus::Ok,
Self::Failed(_) => MetaCallStatus::Failed,
Self::TimeoutOrHeartbeat(_) => MetaCallStatus::TimeoutOrHeartbeat,
Self::Unsupported(_) => MetaCallStatus::Unsupported,
}
}
#[must_use]
pub const fn code(&self) -> Option<LeanDiagnosticCode> {
match self {
Self::Ok(_) => None,
Self::Failed(_) | Self::TimeoutOrHeartbeat(_) => Some(LeanDiagnosticCode::Elaboration),
Self::Unsupported(_) => Some(LeanDiagnosticCode::Unsupported),
}
}
}
impl<'lean, Resp> TryFromLean<'lean> for LeanMetaResponse<Resp>
where
Resp: TryFromLean<'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, "MetaResponse.ok")?;
Ok(Self::Ok(Resp::try_from_lean(payload)?))
}
1 => {
let [payload] = take_ctor_objects::<1>(obj, 1, "MetaResponse.failed")?;
Ok(Self::Failed(LeanElabFailure::try_from_lean(payload)?))
}
2 => {
let [payload] = take_ctor_objects::<1>(obj, 2, "MetaResponse.timeoutOrHeartbeat")?;
Ok(Self::TimeoutOrHeartbeat(LeanElabFailure::try_from_lean(payload)?))
}
3 => {
let [payload] = take_ctor_objects::<1>(obj, 3, "MetaResponse.unsupported")?;
Ok(Self::Unsupported(LeanElabFailure::try_from_lean(payload)?))
}
other => Err(conversion_error(format!(
"expected Lean MetaResponse ctor (tag 0..=3), found tag {other}"
))),
}
}
}