use std::{
ffi::{
c_char,
CStr,
},
panic::{
self,
UnwindSafe,
},
};
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum QuestError {
InvalidQuESTInputError {
err_msg: String,
err_func: String,
},
NulError(std::ffi::NulError),
IntoStringError(std::ffi::IntoStringError),
ArrayLengthError,
}
#[allow(non_snake_case)]
#[no_mangle]
unsafe extern "C" fn invalidQuESTInputError(
errMsg: *const c_char,
errFunc: *const c_char,
) {
let err_msg = unsafe { CStr::from_ptr(errMsg) }.to_str().expect(
"String (errMsg) returned by QuEST should be properly formatted",
);
let err_func = unsafe { CStr::from_ptr(errFunc) }.to_str().expect(
"String (errFunc) returned by QuEST should be properly formatted",
);
log::error!("QueST Error in function {err_func}: {err_msg}");
panic::resume_unwind(Box::new(QuestError::InvalidQuESTInputError {
err_msg: err_msg.to_owned(),
err_func: err_func.to_owned(),
}));
}
pub fn catch_quest_exception<T, F>(f: F) -> Result<T, QuestError>
where
F: FnOnce() -> T + UnwindSafe,
{
panic::catch_unwind(f).map_err(|e| match e.downcast::<QuestError>() {
Ok(boxed_err) => *boxed_err,
Err(e) => panic::resume_unwind(e),
})
}
#[cfg(test)]
mod tests {
use std::thread;
use crate::{
ComplexMatrixN,
PauliHamil,
};
#[test]
fn catch_exception_01() {
let _ = ComplexMatrixN::try_new(1).unwrap();
let _ = ComplexMatrixN::try_new(0).unwrap_err();
}
#[test]
fn catch_exception_02() {
let _ = PauliHamil::try_new(-11, -3).unwrap_err();
let _ = PauliHamil::try_new(2, 2).unwrap();
}
#[test]
fn catch_exception_parallel_01() {
thread::scope(|s| {
s.spawn(|| {
catch_exception_01();
catch_exception_01();
});
s.spawn(|| {
catch_exception_01();
catch_exception_01();
});
});
}
#[test]
fn catch_exception_parallel_02() {
thread::scope(|s| {
s.spawn(|| {
catch_exception_02();
catch_exception_02();
});
s.spawn(|| {
catch_exception_02();
catch_exception_02();
});
});
}
#[test]
fn catch_exception_parallel_03() {
thread::scope(|s| {
s.spawn(|| {
catch_exception_parallel_01();
catch_exception_parallel_02();
});
s.spawn(|| {
catch_exception_parallel_02();
catch_exception_parallel_01();
});
});
}
}