Comment by CryZe
> It's not like you can rely on Rust references and C pointers being identical in the ABI either.
You absolutely can rely on that: https://doc.rust-lang.org/reference/type-layout.html#pointer...
In fact, it's almost even best practice to do so, because it reduces the unsafe needed on Rust's side. E.g. if you want to pass a nullable pointer to T, declare it as e.g. a parameter x: Option<&T> on the Rust side and now can you do fully safe pattern matching as usual to handle the null case.
Want to use some Rust type (not even repr(C)) from C? Just do something like this:
#[no_mangle] pub extern "C" fn Foo_new() -> Box<Foo> { Box::new(Foo::new()) }
#[no_mangle] pub extern "C" fn Foo_free(_: Box<Foo>) { /* automatic cleanup */ }
#[no_mangle] pub extern "C" fn Foo_do_something(this: &mut Foo) { this.do_something() }
all fully safe. Unfortunately for the OP, Vec<_> isn't FFI safe, so that's still one of those cases that are on the rough side.
> Pointers and references have the same layout.
> The layout of a type is its size, alignment, and the relative offsets of its fields.
So “layout” only constrains the memory addresses where a value and its constituents are stored; it does not cover niches. Pointers are allowed to be null, references are not. There is talk of making it illegal to have a reference be unaligned, or even point to very low addresses: <https://github.com/rust-lang/rfcs/pull/3204>. At one point, there was even talk of certain kinds of references not even being stored as memory addresses at all: <https://github.com/rust-lang/rfcs/pull/2040>. And Box<_> is not #[repr(transparent)] either. To put it more generally, the only semantics of a Box<_> or a reference is that it grants you access to a value of a given type and is inter-convertible with a pointer. Only *const _ and *mut _ have a guaranteed ABI.
Just because you write fewer “unsafe” keywords does not mean your code is more safe.