mozilla / cbindgen

A project for generating C bindings from Rust code
Mozilla Public License 2.0
2.37k stars 305 forks source link

Feature request: transparent/erased typedefs #967

Open scovich opened 4 months ago

scovich commented 4 months ago

Today, cbindgen has special-case handling for certain well-known standard types. For example:

This is safe because of the semantics of those types (they somehow act transparent, even tho most of them are not actually #[repr(transparent)]).

Meanwhile, cbindgen supports user-defined #[repr(transparent)] structs by erasing them to typedefs:

#[repr(transparent)]
struct Foo(i32)

is (partly) erased to:

typedef int32_t Foo

However, typedefs (whether user-specified or replacing transparent structs) do not mix cleanly with special-case handling. So, for example, the following all cause cbindgen to emit opaque struct definitions for well-known types instead of optimizing them away correctly:

#[repr(transparent)]
struct Foo(NonNull<i32>);
type NullableFoo = Option<Foo>;

type Function = extern "C" fn(i: i32) -> i64;
type NullableFunction = Option<Function>;

This happens because simplify_standard_types only works for... well-known standard types. Users have no way to opt into similar semantics for their own typedefs and transparent structs.

One possible solution (prototyped as https://github.com/mozilla/cbindgen/pull/966) is to introduce /// cbindgen:transparent-typedef annotation that causes cbindgen to replace transparent structs and typedefs with their underlying type. This allows the following:

/// cbindgen:transparent-typedef
#[repr(transparent)]
struct Foo(NonNull<i32>);

/// cbindgen:transparent-typedef
type Function = extern "C" fn(i: i32) -> i64;

type NullableFoo = Option<Foo>;
type NullableFunction = Option<Function>;

to export as

typedef i32 *NullableFoo;
typedef int64_t (*NullableFunction)(int32_t);

instead of today's output:

template<typename T = void>
struct Option;

using Foo = int32_t*;
using Function = int64_t(*)(int32_t i);

using NullableFoo = Option<Foo>;
using NullableFunction = Option<Function>;
scovich commented 3 months ago

@emilio any thoughts about this?