I'm writing a Rust library which is a wrapper over a C++ library.
Here is the C++ side:
#define Result(type,name) typedef struct { type value; const char* message; } name
extern "C"
{
Result(double, ResultDouble);
ResultDouble myFunc()
{
try
{
return ResultDouble{value: cv::someOpenCvMethod(), message: nullptr};
}
catch( cv::Exception& e )
{
const char* err_msg = e.what();
return ResultDouble{value: 0, message: err_msg};
}
}
}
and corresponding Rust side:
#[repr(C)]
struct CResult<T> {
value: T,
message: *mut c_char,
}
extern "C" {
fn myFunc() -> CResult<c_double>;
}
pub fn my_func() -> Result<f64, Cow<'static, str>> {
let result = unsafe { myFunc() };
if result.message.is_null() {
Ok(result.value)
} else {
unsafe {
let str = std::ffi::CString::from_raw(result.message);
let err = match str.into_string() {
Ok(message) => message.into(),
_ => "Unknown error".into(),
};
Err(err)
}
}
}
I have two questions here:
- Is it ok that I use
*const char
on C++ side but*mut c_char
on Rust one? I need it becauseCString::from_raw
requires mutable reference. - Should I use
CStr
instead? If yes, how should I manage its lifetime? Should I free this memory or maybe it has static lifetime?
Generally I just want to map a C++ exception which occurs in FFI call to Rust Result<T,E>
What is the idiomatic way to do it?