NonZeroU128 through FFI

Hello,

I need to manipulate a Rust ID type from C, which looks like this:

#[repr(transparent)]
pub struct RustId(pub NonZeroU128);

Since u128 is not FFI-safe, and since I'd like to avoid allocating memory everywhere if possible, I've created these helper structs and functions:

#[repr(C)]
pub struct c_id {
    _data: [u8; 16],
}

#[repr(C)]
pub struct opt_c_id {
    pub has_value: bool,
    pub value: c_id,
}

#[no_mangle]
pub extern "C" fn c_id_new(value: u64) -> opt_c_id {
    match NonZeroU128::new(value as u128) {
        Some(value) => opt_c_id {
            has_value: true,
            value: unsafe { mem::transmute::<NonZeroU128, c_id>(value) },
        }
        None => opt_c_id {
            has_value: false,
            value: c_id { _data: [0; 16] },
        }
    }
}

#[no_mangle]
pub extern "C" fn c_id_display(id: c_id) {
    // Probably check to see if the array is full of zeroes here.
    let id = unsafe { mem::transmute::<c_id, RustId>(id) };
    println!("{}", id.0);
}

I can then make use of this API like so:

#include "id.h"

int main() {
    opt_c_id opt_id = c_id_new(42);
    if (opt_id.has_value) {
        c_id id = opt_id.value;
        c_id_display(id);
    }
    return 0;
}

But is it actually safe? Is this approach valid or is there another way? I will have a lot of these types around, so allocating memory each time to then cast to *mut c_void seems bad to me.

For full reference, here is the header file as generated by cbindgen:

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct c_id {
  uint8_t _data[16];
} c_id;

typedef struct opt_c_id {
  bool has_value;
  struct c_id value;
} opt_c_id;

struct opt_c_id c_id_new(uint64_t value);

void c_id_display(struct c_id id);

Thanks in advance for your replies.

You can use u128::to_ne_bytes() and u128::from_ne_bytes() to safely convert between a u128 and a [u8; 16] array. Otherwise, your approach looks entirely sound.

3 Likes

Indeed these two functions can be of great help here. Thanks for checking the soundness of the code.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.