Skip to content

Parsing of Option<NonZero<T>> #95

@RivenSkaye

Description

@RivenSkaye

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions