I need a field to be the the very first field of a struct for use with things like GS relative addressing on x86 but have no other layout requirements on the struct.
The obvious solution is to just use an extern struct but that forces C compatible types for all other fields:
pub const Cpu = extern struct {
// must be the first field `@intFromPtr(&cpu) == @intFromPtr(&cpu.self) == @intFromPtr(cpu.self)`
self: *Cpu,
// the rest of this struct has no need to be extern and wants to contain
// slices, auto layout structs, etc but instead has to contort itself to
// C compatible types
// some fields are read/modified by assembly, getting the offsets of
// those fields is `@offsetOf(Cpu, "field")`
};
My current solution is to use an extern wrapper and embed the inner struct manually:
pub const Cpu = struct {
// can have anything we want here
// some fields of `Cpu` are read/modified by assembly
// getting the offsets of those fields is `@offsetOf(Outer, "_cpu") + @offsetOf(Cpu, "field")`
pub const Outer = extern struct {
// must be the first field `@intFromPtr(&outer) == @intFromPtr(&outer.self) == @intFromPtr(outer.self)`
self: *Outer,
// can't have `cpu: Cpu` as it is an auto type so we need to just slot it in manually
_cpu: [@sizeOf(Cpu)]u8 align(@alignOf(Cpu)),
pub fn cpu(outer: *Outer) *Cpu {
return @ptrCast(&outer._cpu);
}
};
};
Does anyone know of a better way of doing this?