cbindgen icon indicating copy to clipboard operation
cbindgen copied to clipboard

Support generating opaque type with correct size and alignment for non-`#[repr(C)]` types

Open jrmuizel opened this issue 8 years ago • 15 comments

We talked about this a bit at the SF all-hands. If we use '-Z print-type-sizes' we can figure out the size of a non-repr(C) type and make an opaque C type of the same size and alignment.

@Gankro is going to explore what a stable version of '-Z print-type-sizes' would be.

jrmuizel avatar Jul 10 '17 20:07 jrmuizel

Yeah that should be do-able. I'll try and prototype something sometime.

eqrion avatar Jul 10 '17 22:07 eqrion

I have prepared a proposal that I'll be submitting to internals.rust-lang.org

https://gist.github.com/Gankro/b4aa176f4db24671be66f2a3c57e487b

Gankra avatar Jul 10 '17 22:07 Gankra

That proposal seems reasonable from a cbindgen perspective,

If we're attempting to provide fields equivalent to repr(rust) we'll need to parse $type_name with syn. But that shouldn't be a problem.

eqrion avatar Jul 10 '17 23:07 eqrion

The proposal seems good. I think we need to come up with some more motivating examples. I tried to do this last night but struggled a bit. I'm going to think more.

jrmuizel avatar Jul 11 '17 13:07 jrmuizel

I think it's good enough to kick off discussion; posted here: https://internals.rust-lang.org/t/stabilizing-a-machine-readable-zprint-type-sizes/5525

Gankra avatar Jul 11 '17 13:07 Gankra

Gentle ping - we would very much appreciate this in wgpu.

kvark avatar Jan 13 '20 15:01 kvark

I am no longer of the opinion that it's a good idea to use things like -Zprint-type-sizes or other such hacks. The original premise of this bug is flawed, you need detailed information on the shape of the struct, as I discuss here:

https://gankra.github.io/blah/rust-layouts-and-abis/#abi

Gankra avatar Jan 13 '20 16:01 Gankra

@kvark why is this useful?

emilio avatar Jan 14 '20 12:01 emilio

@emilio if I understand correctly, it would allow us to put opaque (from C++ point of view) types (by value) into repr(C) structs that C++ passes around (from Rust to Rust).

kvark avatar Jan 14 '20 16:01 kvark

So you want to put non-repr(C) stuff inside repr(C) structs and pass those by value?

That sounds to me like, unless those types are very simple, it could go wrong (if they're supposed to have destructors and such)... Do you have any concrete use case? But anyhow given rustc's type layout is basically undefined, and cbindgen doesn't hook into rustc, this is not quite easy.

emilio avatar Jan 14 '20 16:01 emilio

#[repr(C)]
struct Foo {
  map: HashMap<i32, i32>,
}

extern "C" fn foo_set(foo: &mut Foo, key: i32, value: i32) {
  foo.map.insert(key, value);
}

extern "C" fn foo_finalize(foo: Foo) {
  println!("{:?}", foo);
  // destructor is called here
}

kvark avatar Jan 14 '20 16:01 kvark

So the only thing that it potentially allows you is to avoid a heap allocation, right?

emilio avatar Jan 14 '20 18:01 emilio

More specifically, allows to avoid indirection on every access.

kvark avatar Jan 14 '20 20:01 kvark

I am strongly interested in this feature as well. Specifically we would like to write code like this:

pub struct Foo { .. }

extern "C" unsafe fn foo_new(ptr: *mut Foo, data: &Bar) {
    core::ptr::write(ptr, Foo::new(data));
}

extern "C" fn foo_do_stuff(foo: &mut Foo, ..)  { .. }

Not only it will be more efficient (since users will be able to use stack-allocated Foo), but also will allow us to make our library completely allocation-free.

newpavlov avatar Aug 19 '20 12:08 newpavlov

Possibly relevant, I did something like this in https://verdagon.dev/blog/exploring-seamless-rust-interop-part-1

The tricky parts:

  • #[repr(align(n))] only works if there's an aligned_n entry in the cbindgen.toml
  • We needed a MaybeUninit<T> to avoid some undefined behavior when we transmuted something into the opaque type.
  • Getting the right size for the opaque type required running a program first that prints it out.

Verdagon avatar May 26 '24 00:05 Verdagon