Description
In error.rs we define a repr(u32)
enum, rustls_result
, and use it throughout the API as an ABI-stable, FFI-friendly way of representing what a Rustacean would probably write as Result<(), NonZero<u32>>
. This is mechanically safe, but also makes the Rust code awkward, in particular precluding use of ?
. It also reduces type-safety by using the same type for both success and error (rustls_result::OK
& rustls_result::*
vs Ok(())
& Err(_)
variants).
It was pointed out to me a while ago by @complexspaces that Result
is documented to have the same stable ABI/repr as Option<T>
, subject to some caveats. The docs say:
In some cases, Result<T, E> will gain the same size, alignment, and ABI guarantees as Option has. One of either the T or E type must be a type that qualifies for the Option representation guarantees, and the other type must meet all of the following conditions:
- Is a zero-sized type with alignment 1 (a “1-ZST”).
- Has no fields.
- Does not have the #[non_exhaustive] attribute.
For example, NonZeroI32 qualifies for the Option representation guarantees, and () is a zero-sized type with alignment 1, no fields, and it isn’t non_exhaustive. This means that both Result<NonZeroI32, ()> and Result<(), NonZeroI32> have the same size, alignment, and ABI guarantees as Option. The only difference is the implied semantics:
- Option 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 think changing our API to use Result<(), NonZeroU32>
would be an ergonomics/safety improvement for the Rust code assuming there aren't any additional "gotchas" lurking here. My thinking is we would rename rustls_result
to rustls_error
and remove the rustls_result::Ok
value.
From an API compatibility standpoint my main concern is how invasive this will be due to rustls_result::Ok
being defined as 7000
presently. AIUI a caller that got an Ok(())
from an extern "C" fn rustls_foo() -> Result<(), NonZeroU32>
would now have 0
in hand, as opposed to 7000
. This is mainly a concern if someone wasn't using the .h
constants (e.g. if(rr == 7000)
vs if(rr == RUSTLS_RESULT_OK)
) - it seems to me it's fair to say those people (if they exist) are already begging for bugs?
We have a sem-ver incompatible 0.15.0 release coming up Soon ™️ so maybe we should do this?