inline fn setExtraField(buffer: []u32, i: usize, comptime Field: type, value: anytype) usize {
switch (@typeInfo(Field)) {
.void => return 0,
.int => |info| switch (info.bits) {
32 => {
buffer[i] = value;
return 1;
},
64 => {
buffer[i..][0..2].* = @bitCast(value);
return 2;
},
else => comptime unreachable,
},
.@"enum" => {
buffer[i] = @backingInt(value);
return 1;
},
.@"struct" => |info| switch (info.layout) {
.@"packed" => switch (info.backing_integer.?) {
u32 => {
buffer[i] = @bitCast(value);
return 1;
},
u64 => {
buffer[i..][0..2].* = @bitCast(value);
return 2;
},
else => comptime unreachable,
},
.auto => switch (Field) {
std.Target.Cpu.Feature.Set => {
const casted: []const u32 = @ptrCast(&value.ints);
@memcpy(buffer[i..][0..casted.len], casted);
return casted.len;
},
else => switch (Field.storage) {
.flag_optional, .enum_optional => {
return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0;
},
.flag_union => return switch (value.u) {
inline else => |x| setExtraField(buffer, i, @TypeOf(x), x),
},
.extended => @compileError("unimplemented"),
.flag_length_prefixed_list => {
const len: u32 = @intCast(value.slice.len);
if (len == 0) return 0; // Flag bit hides the length prefix.
buffer[i] = len;
const buf_len = len * @divExact(@sizeOf(Field.Elem), @sizeOf(u32));
@memcpy(buffer[i + 1 ..][0..buf_len], @as([]const u32, @ptrCast(value.slice)));
return 1 + buf_len;
},
.length_prefixed_list => {
const len: u32 = @intCast(value.slice.len);
buffer[i] = len;
const buf_len = len * @divExact(@sizeOf(Field.Elem), @sizeOf(u32));
@memcpy(buffer[i + 1 ..][0..buf_len], @as([]const u32, @ptrCast(value.slice)));
return 1 + buf_len;
},
.flag_list => {
const len: u32 = @intCast(value.slice.len);
@memcpy(buffer[i..][0..len], @as([]const u32, @ptrCast(value.slice)));
return len;
},
.multi_list => {
const len: u32 = @intCast(value.mal.len);
buffer[i] = len;
const field_names = @typeInfo(Field.Elem).@"struct".field_names;
inline for (0..field_names.len) |field_i| @memcpy(
buffer[i + 1 + field_i * len ..][0..len],
@as([]const u32, @ptrCast(value.mal.items(@fromBackingInt(@intCast(field_i))))),
);
return 1 + field_names.len * len;
},
.union_list => {
if (value.len == 0) return 0;
const Tag = @typeInfo(Field.Union).@"union".tag_type.?;
const slice_ptr: [*]const Field.Union = @ptrCast(@alignCast(value.data));
const slice = slice_ptr[0..value.len];
const meta_buffer = buffer[i..][0 .. (slice.len * @bitSizeOf(Field.Meta) + 31) / 32];
for (slice[0 .. slice.len - 1], 0..) |elem, elem_index| {
const union_tag: Tag = elem;
storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
.tag = union_tag,
.last = false,
}));
} else {
const elem_index = slice.len - 1;
const elem = slice[elem_index];
const union_tag: Tag = elem;
storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
.tag = union_tag,
.last = true,
}));
}
var total: usize = meta_buffer.len;
for (i + meta_buffer.len.., slice) |elem_index, src| switch (src) {
inline else => |x| total += setExtraField(buffer, elem_index, @TypeOf(x), x),
};
return total;
},
},
},
.@"extern" => {
const n = @divExact(@sizeOf(Field), @sizeOf(u32));
const ptr: *align(@alignOf(Field)) const [n]u32 = @ptrCast(&value);
buffer[i..][0..n].* = ptr.*;
return n;
},
},
else => @compileError("bad field type: " ++ @typeName(Field)),
}
}