Description
I am writing an FFI wrapper for a library that has a function returning an integer error code:
extern "C" fn foo() -> libc::c_int;
The error code of foo
is 0
on success and non-zero on error. As suggested by @kennytm , I can do the following dance to obtain a NonZeroU{width}
type that's suitable to hold a c_int
(note: NonZero<libc::c_int>
does not work anymore, and the NonZeroI{width}
variants have been removed, so more extra dance is then necessary to convert the unsigned integers to a libc::c_int
to be able to compare this with with std error codes like libc::EINVAL
):
pub trait NonZeroUInt { type NonZero; }
impl NonZeroUInt for i32 { type NonZero = core::num::NonZeroU32; }
impl NonZeroUInt for i64 { type NonZero = core::num::NonZeroU64; }
impl NonZeroUInt for isize { type NonZero = core::num::NonZeroUsize; }
pub type NonZeroCInt = <libc::c_int as NonZeroUInt>::NonZero;
However, when I then try to use Result
in FFI:
extern "C" fn foo() -> Result<(), NonZeroCInt>;
I get an error stating that Result
is not FFI-safe. This type is really similar to an Option<&'static 32>
which is FFI-safe: an enum with 2 variants, one is zero sized, and the other has niches.
Option<NonNull<*mut i32>>
, Option<NonZeroU32>
, and Result<(), NonZeroU32>
are not, however, FFI safe.
Is this an oversight ?
cc @eddyb @SimonSapin