diff --git a/src/root.rs b/src/root.rs index 3f9579f..99fc2db 100644 --- a/src/root.rs +++ b/src/root.rs @@ -24,10 +24,45 @@ impl core::fmt::Debug for Root { impl Eq for Root {} +// Adaptation from C++: https://gitlab.com/ocaml-rust/ocaml-boxroot/-/blob/c119eb0c88f3f628e683ee90f1b694b51c60a0cb/boxroot/cpp/boxroot.cpp +fn boxroot_raise_error() -> ! { + use ocaml_boxroot_sys::Status; + let status = unsafe { ocaml_boxroot_sys::boxroot_status() }; + let error_message = match status { + Status::ToreDown => "boxroot_teardown has previously been called", + Status::Invalid => "With systhreads, boxroot_setup must be called after caml_thread_initialize but before any thread is created", + Status::Running | Status::NotSetup => { + #[cfg(not(feature = "no-std"))] + { + use std::io::{Error, ErrorKind}; + match Error::last_os_error().kind() { + ErrorKind::PermissionDenied => { + "You tried calling boxroot_create or boxroot_modify without holding the domain lock" + } + ErrorKind::OutOfMemory => { + "Allocation failure of the backing store" + } + _ => "Unknown Error::last_os_error().kind()", + } + } + #[cfg(feature = "no-std")] + { + "Unknown error (details unavailable in no-std environment)" + } + } + _ => "Unknown ocaml_boxroot_sys::Status", + }; + + panic!("Boxroot error: {}", error_message); +} + impl Root { /// Create a new root pub unsafe fn new(v: sys::Value) -> Root { - Root(ocaml_boxroot_sys::boxroot_create(v).expect("boxroot_create failed")) + match ocaml_boxroot_sys::boxroot_create(v) { + Some(root) => Root(root), + None => boxroot_raise_error(), + } } /// Get value from root