#![allow(unsafe_code)]
use std::marker::PhantomData;
use std::panic::{self, AssertUnwindSafe};
use std::ptr::NonNull;
use std::sync::OnceLock;
#[cfg(doc)]
use crate::error::HostStage;
use crate::error::{LeanError, LeanResult};
pub struct LeanRuntime {
_no_send_no_sync: PhantomData<*mut ()>,
}
impl LeanRuntime {
pub fn init() -> LeanResult<&'static Self> {
let _span = tracing::info_span!(target: "lean_rs", "lean_rs.runtime.init").entered();
match INIT.get_or_init(do_initialize_once) {
Ok(()) => {
if lean_rs_sys::supported_for(lean_rs_sys::LEAN_VERSION).is_none() {
tracing::error!(
target: "lean_rs",
code = crate::error::LeanDiagnosticCode::RuntimeInit.as_str(),
version = lean_rs_sys::LEAN_VERSION,
"active Lean toolchain not in the supported window",
);
return Err(LeanError::runtime_init_unsupported_toolchain(lean_rs_sys::LEAN_VERSION));
}
tracing::debug!(
target: "lean_rs",
resolved_version = lean_rs_sys::LEAN_RESOLVED_VERSION,
discovered_version = lean_rs_sys::LEAN_VERSION,
"Lean runtime initialized",
);
super::thread::mark_calling_thread_permitted();
Ok(static_ref())
}
Err(err) => {
tracing::error!(
target: "lean_rs",
code = crate::error::LeanDiagnosticCode::RuntimeInit.as_str(),
"Lean runtime initialization failed",
);
Err(err.clone())
}
}
}
}
impl std::fmt::Debug for LeanRuntime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LeanRuntime").finish()
}
}
static INIT: OnceLock<Result<(), LeanError>> = OnceLock::new();
fn do_initialize_once() -> Result<(), LeanError> {
let outcome = panic::catch_unwind(AssertUnwindSafe(|| {
let workers = read_num_threads_env();
unsafe {
lean_rs_sys::init::lean_initialize_runtime_module();
lean_rs_sys::init::lean_initialize();
match workers {
Some(n) => lean_rs_sys::init::lean_init_task_manager_using(n),
None => lean_rs_sys::init::lean_init_task_manager(),
}
}
}));
match outcome {
Ok(()) => Ok(()),
Err(payload) => Err(LeanError::runtime_init_panic(payload.as_ref())),
}
}
fn read_num_threads_env() -> Option<u32> {
let raw = std::env::var("LEAN_RS_NUM_THREADS").ok()?;
match raw.trim().parse::<u32>() {
Ok(n) if n >= 1 => Some(n),
_ => {
tracing::warn!(
target: "lean_rs",
value = %raw,
"LEAN_RS_NUM_THREADS must be a positive integer; falling back to the Lean default",
);
None
}
}
}
fn static_ref() -> &'static LeanRuntime {
unsafe { NonNull::<LeanRuntime>::dangling().as_ref() }
}