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.typev.uv.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.
