cbindgen icon indicating copy to clipboard operation
cbindgen copied to clipboard

Feature Request: allow specifying that a union should be anonymous

Open morrisonlevi opened this issue 4 months ago • 0 comments

I'd like to be able to mark unions that should be anonymous. As an example:

use core::mem::ManuallyDrop;

/// cbindgen:prefix-with-name=false
/// cbindgen:rename-all=ScreamingSnakeCase
#[repr(C)]
pub enum ResultTag {
    ResultOk,
    ResultErr,
}

/// cbindgen:make-anonymous=true
#[repr(C)]
pub union ResultValue<T, E> {
    pub ok: ManuallyDrop<T>,
    pub err: ManuallyDrop<E>,
}

#[repr(C)]
pub struct Result<T, E> {
    pub tag: ResultTag,

    // alternatively, it could go at the usage site
    // instead of the definition site.
    pub value: ResultValue<T, E>,
}

#[no_mangle]
pub unsafe extern "C" fn result() -> Result<usize, *const u8> {
    todo!()
}

Could generate this, depending on settings:

typedef enum ResultTag {
  RESULT_OK,
  RESULT_ERR,
} ResultTag;

typedef struct Result_usize_______u8 {
  enum ResultTag tag;
  union {
    size_t ok;
    const uint8_t *err;
  } value;
} Result_usize_______u8;

struct Result_usize_______u8 result(void);

To some degree, this is an alternative to unifying generic tags (which has been difficult to get all edges right). I hope the implementation is simpler because cbindgen can already emit an anonymous union, as it already does it for enums:

#[repr(C)]
pub enum Result<T, E> {
    Ok(T),
    Err(E),
}
typedef enum Result_usize_______u8_Tag {
  Ok_usize_______u8,
  Err_usize_______u8,
} Result_usize_______u8_Tag;

typedef struct Result_usize_______u8 {
  Result_usize_______u8_Tag tag;
  union {
    struct {
      size_t ok; 
    };  
    struct {
      const uint8_t *err;
    };  
  };  
} Result_usize_______u8;

But this isn't only about generic types. There may be value in generating anonymous structs as well. For instance, I see anonymous structs and unions in C code fairly regularly, so wanting match the same API with a new implementation written in Rust seems like it would be valuable. PHP does this kind of thing with both structs and unions:

struct _zval_struct {
	zend_value        value;			/* value */
	union {
		uint32_t type_info;
		struct {
			ZEND_ENDIAN_LOHI_3(
				uint8_t    type,			/* active type */
				uint8_t    type_flags,
				union {
					uint16_t  extra;        /* not further specified */
				} u)
		} v;
	} u1;
	union {
		uint32_t     next;                 /* hash collision chain */
		uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */
		uint32_t     opline_num;           /* opline number (for FAST_CALL) */
		uint32_t     lineno;               /* line number (for ast nodes) */
		uint32_t     num_args;             /* arguments number for EX(This) */
		uint32_t     fe_pos;               /* foreach position */
		uint32_t     fe_iter_idx;          /* foreach iterator index */
		uint32_t     guard;                /* recursion and single property guard */
		uint32_t     constant_flags;       /* constant flags */
		uint32_t     extra;                /* not further specified */
	} u2;
};

But I would at least like to be able to do this for unions, as many unions are anonymous today and are very convenient this way.

morrisonlevi avatar Aug 15 '25 17:08 morrisonlevi