C structure and union types can include anonymous unions or anonymous structs. (The C11 standard allows this, and C compilers have allowed it for decades as an extension.) For instance:
struct Variant {
int type;
union {
uint64_t u;
double d;
};
};
Omitting the field names for such a union or struct embeds its fields directly in the containing struct or union, while keeping the struct/union semantics for field layout and overlap. For instance, the structure above allows the following field accesses:
v.type
v.u
v.d
These constructs also nest arbitrarily. An anonymous union allows overlapping fields that won’t get used at the same time. An anonymous struct within a union allows grouping together multiple fields that need to exist simultaneously. For instance, consider adding a counted string to the above structure:
struct Variant {
int type;
union {
uint64_t u;
double d;
struct {
char *s;
size_t slen;
};
};
};
This allows accessing v.s
and v.slen
.
Note that you can define an inner struct or union without omitting the field name as well:
struct Variant {
int type;
union {
uint64_t u;
double d;
struct {
char *ptr;
size_t len;
} s;
};
};
This version would instead have v.s.ptr
and v.s.len
.
This pattern includes two new constructs that Rust doesn’t have: defining a struct or union type inline inside another, and omitting a field name to make fields part of the parent type.
For a much larger production example, take a look at struct kvm_run
in the Linux KVM API.
This struct-of-unnamed-union-of-structs pattern occurs in many C APIs, so Rust FFIs will need to interface with it.
Rust code could define types compatible with this layout, using unions and structs; however, each union or struct type used in the definition would require a separate definition and name. And worse, when using the resulting aggregate type, each grouping of fields requires a name; for instance, the unnamed union above would require an explicit name and an additional .union_name.
in field accesses.
(Cc @retep998, who will likely want this for Windows APIs.)
I’d like to propose an RFC defining syntax for this.
First, for defining a struct or union inline, while still naming the field:
struct S {
common: u32,
fieldname: union {
field1: u64,
field2: f64,
inner_struct: struct {
inner1: SomeType,
inner2: AnotherType,
},
},
}
This syntax should parse unambiguously, because struct {
or union {
can’t currently appear where the field type would.
This would have the same semantics as defining a new type with no name, and then declaring the corresponding field with that type.
Any derive
or repr
declarations for the top-level struct should automatically apply to the nested types as well, so you can #![derive(Debug),repr(C)]
for struct S
above.
Note that you can still use that anonymous type via inference; for instance:
fn f(s: S) {
let u = &s.fieldname;
println!("{}", u.field1);
}
Finally, for defining an unnamed field:
struct S {
common: u32,
union {
field1: u64,
field2: f64,
struct {
inner1: SomeType,
inner2: AnotherType,
},
},
}
This syntax should parse unambiguously, because struct {
or union {
can’t currently appear where the field name would.
This definition effectively inlines all the fields within the top-level structure, while retaining the layout and borrow semantics defined by the struct and union. For instance, after borrowing inner1
you can still borrow common
and inner2
, but you can’t borrow field1
or field2
.