Skip to content

Feature Request: allow specifying that a union should be anonymous #1097

@morrisonlevi

Description

@morrisonlevi

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions