Bindgen and c++ std::array

I am trying to use bindgen on an existing C++ header file format, and I'm running into something I consider odd with how it works with C-style arrays versus C++ std::array. Specifically, bindgen seems to "understand" a C-style array, but completely whiffs on the C++ std::array and makes it an opaque set of bytes, but only if it's a non-primitive. Is there any way to make bindgen understand that a std::array is exactly the same layout as a C-style array?

Input C++ header:

// NestTest.hpp
// Testing nested C-style arrays vs C++ arrays with bindgen

#include <cstdint>
#include <array>

const size_t NESTED_ARRAY_LENGTH = 16;
const size_t CONTAINED_ARRAY_LENGTH = 4;
struct Nested {
    uint8_t marker;
    std::array<uint8_t, NESTED_ARRAY_LENGTH> stdArray;
    uint8_t cArray[NESTED_ARRAY_LENGTH];
};

struct SingleContainer {
    uint8_t header;
    Nested data;
};

struct MyArrayContainer {
    uint8_t header;
    std::array<Nested, CONTAINED_ARRAY_LENGTH> data;
};

struct MyCstyleContainer {
    uint8_t header;
    Nested data[CONTAINED_ARRAY_LENGTH];
};

Bindgen command-line:

 bindgen NestTest.hpp -o testout.rs --allowlist-type MyCstyleContainer --allowlist-type SingleContainer --allowlist-type MyArrayContainer -- -std=c++20

And just the types I'm interested in that are in the output file (there's a bunch of extras, but cleaning that up isn't the problem at hand)

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Nested {
    pub marker: u8,
    pub stdArray: [u8; 16usize],
    pub cArray: [u8; 16usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SingleContainer {
    pub header: u8,
    pub data: Nested,
}
#[repr(C)]
pub struct MyArrayContainer {
    pub header: u8,
    pub data: [u8; 132usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct MyCstyleContainer {
    pub header: u8,
    pub data: [Nested; 4usize],
}

I want MyArrayContainer's translation to be identical to MyCstyleContainer's. Is there any way to do this, to let bindgen know that they should be the same, so I can just use nested types? C-style arrays are horrific in modern C++ (ie: any C++ made in the last 10 years), so anything I've worked with (or created) lately uses std::array. Now that I want to transition to Rust, this is a barrier.

The part that's really bizarre here IMO is in Nested it obviously knows that both array types are really the same thing (for a primitive type, outputs the same). But it won't do it when nesting another type? WTF?

I'd love to learn that there's a simple option that it's just easy to do. Does somebody know how? If not, I know where the bug list for bindgen is on Github!

Does it know? It looks to me like it uses u8 as the Rust array element type for a C++ std::array, and, in Nested, that just happened to match the element type of the C++ std::array. Do the types still match if you change uint8_t to something larger?

Good thought, but it actually works. Change was:

struct Nested {
    uint8_t marker;
    std::array<uint16_t, NESTED_ARRAY_LENGTH> stdArray;
    uint16_t cArray[NESTED_ARRAY_LENGTH];
};

Output:

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Nested {
    pub marker: u8,
    pub stdArray: [u16; 16usize],
    pub cArray: [u16; 16usize],
}

So had to try it, but doesn't show the same behavior. So weirdly inconsistent.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.