╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭───────────────────────────────────────────────────────────────────────╮ │1397 baseline_maybe: ?T, │ │1398 target: T, │ │1399 parent: T, │ │1399 - outcome: *[std.meta.fields(T).len]FieldMerge, │ │1400 + outcome: *[@typeInfo(T).@"struct".field_names.len]FieldMerge,│ │1401 ) T { │ │1402 var merged = target; │ │1403 │ ╰───────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │1403 - inline for (std.meta.fields(T), 0..) |field, i| { │ │1404 - const target_value = @field(target, field.name); │ │1405 - const parent_value = @field(parent, field.name); │ │1404 + const info = @typeInfo(T).@"struct"; │ │1405 + inline for (info.field_names, info.field_types, 0..) |field_name, field_type, i| {│ │1406 + const target_value = @field(target, field_name); │ │1407 + const parent_value = @field(parent, field_name); │ │1408 │ │1407 - if (!fieldEqual(field.type, target_value, parent_value)) { │ │1409 + if (!fieldEqual(field_type, target_value, parent_value)) { │ │1410 outcome[i] = if (baseline_maybe) |baseline| blk: { │ │1409 - const baseline_value = @field(baseline, field.name); │ │1410 - if (fieldEqual(field.type, target_value, baseline_value)) { │ │1411 - @field(merged, field.name) = parent_value; │ │1411 + const baseline_value = @field(baseline, field_name); │ │1412 + if (fieldEqual(field_type, target_value, baseline_value)) { │ │1413 + @field(merged, field_name) = parent_value; │ │1414 break :blk .parent; │ │1415 } │ │1416 // only the target changed it │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │1415 - if (fieldEqual(field.type, parent_value, baseline_value)) break :blk .kept;│ │1417 + if (fieldEqual(field_type, parent_value, baseline_value)) break :blk .kept;│ │1418 break :blk .conflicted; │ │1419 } else .conflicted; │ │1420 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │1493 const target_records = try DB.HashMap(.read_write).init(target_records_cursor); │ │1494 │ │1495 // a record the target doesn't have arrives wholesale from the parent │ │1494 - var outcome: [std.meta.fields(T).len]FieldMerge = @splat(.parent); │ │1496 + var outcome: [@typeInfo(T).@"struct".field_names.len]FieldMerge = @splat(.parent);│ │1497 var merged = parent_record; │ │1498 │ │1499 if (try target_records.getCursor(record_key)) |target_record_cursor| { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │1593 var conflicted_fields: [conflictedFieldsMaxLen(T)]u8 = undefined; │ │1594 var conflicted_len: usize = 0; │ │1595 │ │1594 - inline for (std.meta.fields(T), 0..) |field, i| { │ │1596 + inline for (@typeInfo(T).@"struct".field_names, 0..) |field_name, i| {│ │1597 switch (outcome[i]) { │ │1598 // the target's value stands, so its oid does too │ │1599 .kept => {}, │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1606 field_oids = try DB.SortedMap(.read_write).init(try id_to_field_to_oid.putCursor(record_key)); │ │1607 } │ │1608 const map = field_oids orelse unreachable; │ │1607 - const parent_oid = if (parent_field_oids) |parent_map| try parent_map.getCursor(field.name) else null;│ │1609 + const parent_oid = if (parent_field_oids) |parent_map| try parent_map.getCursor(field_name) else null;│ │1610 if (parent_oid) |oid_cursor| { │ │1609 - try map.put(field.name, .{ .slot = oid_cursor.slot() }); │ │1611 + try map.put(field_name, .{ .slot = oid_cursor.slot() }); │ │1612 } else { │ │1611 - _ = try map.remove(field.name); │ │1613 + _ = try map.remove(field_name); │ │1614 } │ │1615 }, │ │1616 .conflicted => { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1618 conflicted_fields[conflicted_len] = ' '; │ │1619 conflicted_len += 1; │ │1620 } │ │1619 - @memcpy(conflicted_fields[conflicted_len..][0..field.name.len], field.name);│ │1620 - conflicted_len += field.name.len; │ │1621 + @memcpy(conflicted_fields[conflicted_len..][0..field_name.len], field_name);│ │1622 + conflicted_len += field_name.len; │ │1623 }, │ │1624 } │ │1625 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2090 } │ │2091 │ │2092 fn assertFieldSubset(comptime Sub: type, comptime Full: type) void { │ │2091 - for (@typeInfo(Sub).@"struct".fields) |field| { │ │2092 - if (!@hasField(Full, field.name)) @compileError(@typeName(Full) ++ " has no field " ++ field.name);│ │2093 - const FullField = @FieldType(Full, field.name); │ │2094 - if (@typeInfo(field.type) == .@"struct") { │ │2095 - assertFieldSubset(field.type, FullField); │ │2096 - } else if (field.type != FullField) { │ │2097 - @compileError(@typeName(Full) ++ "." ++ field.name ++ " is a " ++ @typeName(FullField)); │ │2093 + const info = @typeInfo(Sub).@"struct"; │ │2094 + for (info.field_names, info.field_types) |field_name, field_type| { │ │2095 + if (!@hasField(Full, field_name)) @compileError(@typeName(Full) ++ " has no field " ++ field_name);│ │2096 + const FullField = @FieldType(Full, field_name); │ │2097 + if (@typeInfo(field_type) == .@"struct") { │ │2098 + assertFieldSubset(field_type, FullField); │ │2099 + } else if (field_type != FullField) { │ │2100 + @compileError(@typeName(Full) ++ "." ++ field_name ++ " is a " ++ @typeName(FullField)); │ │2101 } │ │2102 } │ │2103 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2112 var event: T = undefined; │ │2113 switch (@typeInfo(T)) { │ │2114 .@"struct" => |struct_info| { │ │2112 - inline for (struct_info.fields) |field| { │ │2113 - const cursor = try map.getCursor(hash.hashInt(hash_kind, field.name)); │ │2114 - @field(event, field.name) = try readField(field.type, DB, hash_kind, arena, cursor);│ │2115 + inline for (struct_info.field_names, struct_info.field_types) |field_name, field_type| {│ │2116 + const cursor = try map.getCursor(hash.hashInt(hash_kind, field_name)); │ │2117 + @field(event, field_name) = try readField(field_type, DB, hash_kind, arena, cursor);│ │2118 } │ │2119 }, │ │2120 else => @compileError("read expects a struct"), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2138 const cursor = cursor_maybe orelse return error.NotFound; │ │2139 switch (@typeInfo(Field)) { │ │2140 .pointer => |pointer_info| { │ │2138 - if (pointer_info.size != .slice or pointer_info.child != u8 or !pointer_info.is_const) { │ │2141 + if (pointer_info.size != .slice or pointer_info.child != u8 or !pointer_info.attrs.@"const") {│ │2142 @compileError("unsupported read field type: " ++ @typeName(Field)); │ │2143 } │ │2144 return try cursor.readBytesAlloc(arena.allocator(), null); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯