use std::panic::{AssertUnwindSafe, catch_unwind};
use std::time::{Duration, Instant};
use lean_rs::abi::traits::TryFromLean;
use lean_rs::{LeanCallbackFlow, LeanProgressCallback, LeanResult, Obj};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LeanProgressEvent {
pub phase: &'static str,
pub current: u64,
pub total: Option<u64>,
pub elapsed: Duration,
}
pub trait LeanProgressSink: Send + Sync {
fn report(&self, event: LeanProgressEvent);
}
pub(crate) struct ProgressBridge<'a> {
callback: LeanProgressCallback<'a>,
}
impl<'a> ProgressBridge<'a> {
pub(crate) fn new(sink: &'a dyn LeanProgressSink, phase: &'static str, total: Option<u64>) -> LeanResult<Self> {
let started = Instant::now();
let callback = LeanProgressCallback::register(move |event| {
sink.report(LeanProgressEvent {
phase,
current: event.current,
total,
elapsed: started.elapsed(),
});
LeanCallbackFlow::Continue
})?;
Ok(Self { callback })
}
pub(crate) fn abi_parts(&self) -> (usize, usize) {
self.callback.abi_parts()
}
pub(crate) fn decode<'lean, T>(&self, obj: Obj<'lean>) -> LeanResult<T>
where
T: TryFromLean<'lean>,
{
self.callback.decode_result(obj)
}
}
pub(crate) fn report_progress(
sink: Option<&dyn LeanProgressSink>,
phase: &'static str,
current: u64,
total: Option<u64>,
started: Instant,
) -> LeanResult<()> {
let Some(sink) = sink else {
return Ok(());
};
let event = LeanProgressEvent {
phase,
current,
total,
elapsed: started.elapsed(),
};
catch_unwind(AssertUnwindSafe(|| sink.report(event)))
.map_err(|payload| lean_rs::__host_internals::host_callback_panic(payload.as_ref()))
}