Crates.io | abienum |
lib.rs | abienum |
version | 0.0.0-2025-01-19 |
created_at | 2025-01-19 11:00:15.356544+00 |
updated_at | 2025-01-19 11:00:15.356544+00 |
description | underlying types for C enums |
homepage | |
repository | https://github.com/MaulingMonkey/abienum |
max_upload_size | |
id | 1522751 |
size | 43,418 |
Attempts to define the implicit underlying types of C and C++ enums, when compiled via the cc
crate using default settings.
That is, enums that follow any of these styles:
enum Test { Hello = 1 };
typedef enum { Hello = 1 } Test;
typedef enum Test { Hello = 1 } Test;
typedef enum _Test { Hello = 1 } Test;
Would presumably be FFI-compatible with the following Rust type:
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)] pub struct Test(abienum::c_enum_u7);
impl Test { pub const Hello : Test = Test(1 as _); }
You are expected to use the c_enum_*
with the smallest compatible range — e.g. c_enum_u7
over c_enum_u8
or c_enum_i8
.
The underlying type of enums is implementation specific, to the point of being potentially finicky in practice.
Compilers may disagree on enum size.
For example, ARM delegates type selection to the platform ABI,
which leads to Clang and GCC disagreeing on enum size for unknown/none, where no platform ABI is specified or agreed upon.
If using the cc
crate, prefer a global CC=...
over .compiler("...")
.
If linking against prebuilt libraries, specify the same compiler as was used for said libraries via CC=...
Compilers provide flags controlling enum size, such as -f[no-]short-enums
[clang,
gcc].
If you need these, prefer a global CFLAGS=...
over .flag("...")
.
Compilers may provide extensions controlling enum size, such as __attribute__((packed))
or #pragma
s.
You're completely on your own for those.
I recommend a lot of static_assert
s on the C++ side and const _ : () = assert!(...);
s on the Rust side.
Good luck.
Compilers may or may not actually respect the flags, attributes, and pragmas specified. E.g. LLVM seems to ignore them on Win32 despite parsing them (llvm/llvm-project #70607)
Type selection beyond the basics (e.g. involving potentially typed expressions that depend on previous enumerands) is enough of a potential mess that I haven't tackled it. See also these C23 proposals:
C++11 (and perhaps C23?) provides syntax to explicitly control the underlying type of enums, which — assuming you can sanely modify the C/C++ — I strongly recommend over resorting to this crate's nonsense:
enum Test : int { Hello = 1 };
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)] pub struct Test(core::ffi::c_int);
impl Test { pub const Hello : Test = Test(1 as _); }
If you're stuck in earlier versions of C or C++, the old "force dword" trick will at least get the size right (signedness may still vary):
typedef enum _D3DLIGHTTYPE {
D3DLIGHT_POINT = 1,
D3DLIGHT_SPOT = 2,
D3DLIGHT_DIRECTIONAL = 3,
D3DLIGHT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */
} D3DLIGHTTYPE;
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)] pub struct D3DLIGHTTYPE(i32);
pub const D3DLIGHT_POINT : D3DLIGHTTYPE = D3DLIGHTTYPE(1);
pub const D3DLIGHT_SPOT : D3DLIGHTTYPE = D3DLIGHTTYPE(2);
pub const D3DLIGHT_DIRECTIONAL : D3DLIGHTTYPE = D3DLIGHTTYPE(3);
// const D3DLIGHT_FORCE_DWORD : D3DLIGHTTYPE = D3DLIGHTTYPE(0x7fffffff); // impl detail
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.