rust-bindgen icon indicating copy to clipboard operation
rust-bindgen copied to clipboard

Generate getters/setters to contained anonymous struct/union members

Open fitzgen opened this issue 8 years ago • 7 comments

We often see code like this:

struct JSJitInfo {
    // ...
    
    union {
        uint16_t protoID;
        js::jit::InlinableNative inlinableNative;
    };

    // ...
};

which generates members and types like __bindgen_anon_1: JSJitInfo__bindgen_ty_1.

It would be cool if we generated getters/setters on the containing struct for these anonymous structs/unions members, so that using them was easier and more like their usage in C/C++.

fitzgen avatar Jun 02 '17 21:06 fitzgen

Not sure if related, but would it be possible to support anonymous structs by flattening their properties (like C does) instead of generating __bindgen_anon_1? That's our primary case for using anonymous struct fields, and I guess we're not alone.

RReverser avatar Jun 28 '17 17:06 RReverser

Assuming that they don't affect the layout of the type, it'd be doable, yeah... But I don't think that's the case, for example:

struct Foo {
    struct {
        uint64_t word;
        uint32_t bar;
    };
    uint32_t baz;
};

I think bar and baz would be collapsed if we flatten the structs, but not otherwise.

emilio avatar Jul 04 '17 10:07 emilio

@emilio Not sure I follow, why would they collapse?

RReverser avatar Jul 04 '17 12:07 RReverser

Oh wait, got it now, you mean because of the padding on 64-bit architecture. Yeah, guess it will need to be still generated as a separate field, but, as far as I remember, bindgen already does that in other places.

RReverser avatar Jul 04 '17 12:07 RReverser

Right, adding padding and alignment bits should be doable, though it may not be as trivial.

emilio avatar Jul 04 '17 15:07 emilio

Will open a different issue about this, seems a somewhat different scope from this one :).

emilio avatar Jul 04 '17 15:07 emilio

This would be nice for my use case, which depends on a third party header.

I'd like to implement it, but would like confirmation on the expected output before I start.

Input:

struct Foo {
    struct {
        uint8_t a;
        uint16_t b;

        union {
            uint8_t reserved1[64];
            uint8_t c;
        };
    };

    union {
        uint8_t reserved2[128];
        struct {
            uint8_t d;
        };
    };
};

Output:

struct Foo {
    pub a: u8,
    pub b: u16,
    // TODO: alignment/padding ^
    
    union_storage_1: [u8; 64],
    // TODO: alignment/padding ^

    union_storage_2: [u8; 128],
    // TODO: alignment/padding ^

    // Consecutive union and padding could be merged, but it doesn't provide significant value.
}

impl Foo {
    #[inline]
    unsafe fn reserved1(&self) -> &[u8; 64] { ... }
    
    // Non-mut primites can be by value
    #[inline]
    unsafe fn c(&self) -> u8 { ... }

    // Mut primites are by mut ref
    #[inline]
    unsafe fn c_mut(&mut self) -> &mut u8 { ... }
    
    // ...
}

Accessors for rust primitives that can store any bit pattern wouldn't necessarily need to be unsafe (e.g. u8), but I wouldn't want to have to deal with that in the first pass.

steven-joruk avatar May 04 '24 02:05 steven-joruk