-
Notifications
You must be signed in to change notification settings - Fork 353
Description
👋 Hi folks,
Since RFC 3391 (rust-lang/rfcs#3391) the Result
type's documentation has a Representation section that describes conditions where Result<T, E>
can have the same size, alignment and ABI guarantees as Option<U>
.
E.g.
For example,
NonZeroI32
qualifies for theOption
representation guarantees, and()
is a zero-sized type with alignment 1, no fields, and it isn’tnon_exhaustive
. This means that bothResult<NonZeroI32, ()>
andResult<(), NonZeroI32>
have the same size, alignment, and ABI guarantees asOption<NonZeroI32>
. The only difference is the implied semantics:
Option<NonZeroI32>
is “a non-zero i32 might be present”
Result<NonZeroI32, ()>
is “a non-zero i32 success result, if any”
Result<(), NonZeroI32>
is “a non-zero i32 error result, if any”
I'm trying to lean on this guarantee to implement FFI for a Rust function that wants to use the implied semantics of returning Result<(), NonZeroU32>
to mean "a non-zero u32 error result, if any":
pub const MAY_FAIL_ARG_ZERO_ERR: u32 = 99;
#[no_mangle]
extern "C" fn may_fail(arg: u32) -> Result<(), NonZeroU32> {
match arg == 0 {
true => Err(NonZeroU32::new(MAY_FAIL_ARG_ZERO_ERR).unwrap()),
false => Ok(()),
}
}
This code compiles, and generates no warnings about unsafe FFI type usage with rust stable.
However, the cbindgen
(0.27.0) result is not what I expect:
#define MAY_FAIL_ARG_ZERO_ERR 99
typedef struct Result_u32 Result_u32;
struct Result_u32 may_fail(uint32_t arg);
If I change may_fail
to return Option<NonZeroU32>
, I get the results I expected, but I've lost the implied semantics I want to maintain on the Rust-side:
#define MAY_FAIL_ARG_ZERO_ERR 99
uint32_t may_fail(uint32_t arg);
Is there a workaround I could use to get cbindgen
to play nice with "stable representation" Result
instances? Is my understanding flawed in some other way?
Thanks!