mod compiled;
mod engine;
mod ep;
mod factory;
mod mlx;
mod ops;
mod registry;
mod sys;
mod trace;
use std::ffi::c_char;
use std::ptr;
use factory::MlxEpFactory;
use sys::ort;
pub(crate) unsafe fn guard_ffi_status(
api: *const ort::OrtApi,
what: &'static str,
body: impl FnOnce() -> *mut ort::OrtStatus,
) -> *mut ort::OrtStatus {
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(body)) {
Ok(status) => status,
Err(payload) => {
let detail = panic_payload_message(&payload);
eprintln!(
"[onnxruntime-mlx] ERROR: caught a panic in {what}: {detail} — returning EP_FAIL; \
ORT will fall back to the CPU EP (host process protected)."
);
if api.is_null() {
return ptr::null_mut();
}
let msg = std::ffi::CString::new(format!(
"onnxruntime-mlx: recovered from a panic in {what}: {detail} (host protected); the operation failed"
))
.unwrap_or_else(|_| {
std::ffi::CString::new("onnxruntime-mlx: recovered from a panic").unwrap()
});
unsafe { ((*api).CreateStatus.unwrap())(ort::OrtErrorCode_ORT_EP_FAIL, msg.as_ptr()) }
}
}
}
pub(crate) fn panic_payload_message(payload: &Box<dyn std::any::Any + Send>) -> String {
if let Some(s) = payload.downcast_ref::<&str>() {
(*s).to_string()
} else if let Some(s) = payload.downcast_ref::<String>() {
s.clone()
} else {
"unrecoverable panic (non-string payload)".to_string()
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn CreateEpFactories(
registration_name: *const c_char,
ort_api_base: *const ort::OrtApiBase,
default_logger: *const ort::OrtLogger,
factories: *mut *mut ort::OrtEpFactory,
max_factories: usize,
num_factories: *mut usize,
) -> *mut ort::OrtStatus {
let api_for_status: *const ort::OrtApi = unsafe {
let get_api = (*ort_api_base).GetApi.unwrap();
let a = get_api(factory::ORT_API_VERSION);
if a.is_null() { get_api(1) } else { a }
};
unsafe {
guard_ffi_status(api_for_status, "CreateEpFactories", || {
CreateEpFactories_impl(
registration_name,
ort_api_base,
default_logger,
factories,
max_factories,
num_factories,
)
})
}
}
#[allow(non_snake_case)]
unsafe fn CreateEpFactories_impl(
registration_name: *const c_char,
ort_api_base: *const ort::OrtApiBase,
_default_logger: *const ort::OrtLogger,
factories: *mut *mut ort::OrtEpFactory,
max_factories: usize,
num_factories: *mut usize,
) -> *mut ort::OrtStatus {
unsafe {
let api_base = &*ort_api_base;
let get_api = api_base.GetApi.unwrap();
let ort_api = get_api(factory::ORT_API_VERSION);
if ort_api.is_null() {
let legacy = get_api(1);
return ((*legacy).CreateStatus.unwrap())(
ort::OrtErrorCode_ORT_INVALID_ARGUMENT,
c"MLXExecutionProvider requires ONNX Runtime with ORT_API_VERSION >= 27".as_ptr(),
);
}
let ep_api = ((*ort_api).GetEpApi.unwrap())();
if max_factories < 1 {
return ((*ort_api).CreateStatus.unwrap())(
ort::OrtErrorCode_ORT_INVALID_ARGUMENT,
c"MLXExecutionProvider needs room for one OrtEpFactory".as_ptr(),
);
}
let factory = MlxEpFactory::new(registration_name, ort_api, ep_api);
*factories.add(0) = factory.as_ptr();
*num_factories = 1;
ptr::null_mut()
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ReleaseEpFactory(factory: *mut ort::OrtEpFactory) -> *mut ort::OrtStatus {
unsafe {
factory::release_factory(factory);
}
ptr::null_mut()
}