You could use repr(transparent) to create a type where you could implement From and that still represent a i32, this allow to compile check that you transform your result correctly assuming you didn't have bug in your from() implementation so maybe add some unit tests.
type MyResult = Result<(), ()>;
fn my_rust_function() -> MyResult {
Ok(())
}
#[repr(transparent)]
pub struct CResult {
code: i32,
// code: libc::c_int, // if your C lib expect a `c_int` and not a `i32`
}
impl From<MyResult> for CResult {
fn from(result: MyResult) -> Self {
let code = match result {
Ok(_) => 1,
Err(_) => -1,
};
Self { code }
}
}
#[allow(non_snake_case)]
pub extern "C" fn Called_From_C() -> CResult {
let result = my_rust_function();
result.into()
}
You could also use enum with repr(i32):
#[repr(i32)]
pub enum CResult {
NoError = 1,
Error = -1,
}
impl From<MyResult> for CResult {
fn from(result: MyResult) -> Self {
match result {
Ok(_) => CResult::NoError,
Err(_) => CResult::Error,
}
}
}
In nightly, you could also implement Try:
#![feature(try_trait)]
use std::ops::Try;
type MyResult = Result<(), ()>;
fn my_rust_function() -> MyResult {
Ok(())
}
#[repr(i32)]
pub enum CResult {
NoError = 1,
Error = -1,
}
impl From<MyResult> for CResult {
fn from(result: MyResult) -> Self {
match result {
Ok(_) => CResult::NoError,
Err(_) => CResult::Error,
}
}
}
impl From<CResult> for MyResult {
fn from(cresult: CResult) -> Self {
match cresult {
CResult::NoError => Ok(()),
CResult::Error => Err(()),
}
}
}
impl Try for CResult {
type Ok = ();
type Error = ();
fn into_result(self) -> MyResult {
self.into()
}
fn from_ok(_: <Self as Try>::Ok) -> Self {
Self::NoError
}
fn from_error(_: <Self as Try>::Error) -> Self {
Self::Error
}
}
#[allow(non_snake_case)]
pub extern "C" fn Called_From_C() -> CResult {
let _ = my_rust_function()?;
CResult::NoError
}
Note: Be careful with the enumeration one, make sure your implementation is compatible. #[repr(libc::c_int)] is what we really want but I don't know any way to express this in Rust. So maybe a structure with repr(transparent) is more safe if the lib expect a c_int.
result.map(|_| 1).map_err(|_| -1).unwrap(), but then you're creating needless closures.