Crate ffi_11

Crate ffi_11 

Source
Expand description

§One to one FFI.

In ffi_11, if a type is distinct in C/C++, it is distinct in Rust. This relationship varies from platform to platform.

For example, char and signed char are distinct types in C++. This means that in ffi_11, there is a distinct ffi_11::c_char type which is not the same as ffi::c_schar, even if char is signed. This is unlike the std::ffi module, which would instead define both c_char and c_schar as aliases to i8.

As another example, on some platforms, int64_t is long, while on other platforms, it is long long. Exactly one of ffi_11::c_long or ffi_11::c_longlong will be i64, depending on the platform.

§Guarantees and backwards compatibility

ffi_11 offers the following guarantees:

  • Every unique C/C++ type is given a unique Rust type: the Rust->C/C++ type mapping is one-to-one.

  • A given type c_<X> is the same type as a builtin iN or uN type if, and only if, the corresponding C++ type is the same type as the standard library (u)intN_t on this platform.

    For example, c_int is i32 if int32_t is a type alias to int. Otherwise, c_int will be a different type. (Either a newtype, or a non-i32 primitive 32 bit integer type.)

There are no type identity guarantees other than the above. For example, long long may be a i64,isize, or a newtype, depending on the platform.

There is also no guarantee that every Rust primitive type has a C++ equivalent. The 1:1 relationship only applies to the types in the ffi_11 module. To get the equivalent high-fidelity interop in C++, you would need an equivalent <ffi_11.h> header, defined in a similar fashion and using newtypes to define C++ types that correspond to Rust primitives that otherwise have no C++ equivalent. (For example, the typical Windows ABI only has one 64 bit integer type, while Rust has two.)

§Supported Operations

The following operations are supported:

  • From: any ffi_11 type can be converted to or from a builtin or ffi_11 type if the conversion is lossless. For example, c_int can always be converted to c_long, but not to c_ulong. And i32 can always be converted to c_int, but i64 can only on some platforms.

  • Separately from the above, c_char can be converted to and from both i8 and u8 using From and Into. It is considered an ambiguously-signed type for portability.

§Supported platforms

For now, the only supported platforms are:

  • LP64: Any LP64 platform which uses the smallest suitable fundamental type for intN_t. For example, Linux on x86_64 or Aarch64. But not OpenBSD.
  • LLP64: 64-bit Windows.

We will add support over time to other commonly used platforms.

TODO(b/333759161): get and test a compatibility matrix, including (currently untested) Windows.

§Unfinished Work

This module is still embryonic, and is missing the following:

  • Support for long long on Linux. This depends on a decision about what the type should be. For example, it could be isize, or a newtype.

  • TryFrom impls for lossy conversions.

  • Any/all other operations (e.g. arithmetic) one might want to support on newtypes.

§References

Structs§

c_char
c_char8_t
c_char16_t
c_char32_t
c_nullptr_t

Enums§

c_void
Equivalent to C’s void type when used as a pointer.

Type Aliases§

c_double
c_float
c_int
c_long
c_schar
c_short
c_uchar
c_uint
c_ulong
c_ushort
c_wchar_t