-
Notifications
You must be signed in to change notification settings - Fork 71
Open
Labels
Description
The NonZero*
integer types (all stemming from std::num::NonZero
) support an FFI-safe Null Pointer Optimization for guaranteeing layout, namely Option<NonZero<T>>
can use the niche of a struct (in this case inputs being 0) to represent the None
case with the same size and alignment as the underlying type. This optimization is specifically defined for NonZero
Looking through the code, I'm not seeing any handling for this (or any other NPOs for that matter) while they can make the Rust code a lot more ergonomic to both read and write. For example:
use std::num::NonZeroU32;
static DEFAULT_NUMBER: i64 = -1;
/// NPO means C# can give us 0 and this code will function!
/// Uses the special-cased "system" calling convention, which will compile to different conventions depending on
// 32-bit or 64-bit Windows targets, as these use different C calling conventions.
#[no_mangle]
pub extern "system" fn convert_int(num: Option<NonZero32>) -> i64 {
match num {
None => DEFAULT_NUMBER,
Some(n) => n as _ // Safe, all values for u32 fit in the positive range of i64
}
}
With the corresponding C# code being able to safely do
var rand = new Random();
uint number = (uint)(rand.Next(0, 2)); // always returns 0 or 1 because the upper bound is exclusive
long conv = convert_int(number)
if (conv < 0) Console.WriteLine("We passed a zero to Rust!")
else Console.WriteLine("We passed a non-zero value!")
And a stable Rust playground for this as well