╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ event.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
535 const baseline_value_cursor = try baseline.getCursor(kv_pair.hash) orelse { 536 if ((try target.getCursor(kv_pair.hash)) != null) { 537 return error.MergeConflict; 538 } 539 540 try target.put(kv_pair.hash, .{ .slot = kv_pair.value_cursor.slot() }); 541 continue; 542 }; 543 544 const tag = kv_pair.value_cursor.slot().tag; 545 546 if (tag != baseline_value_cursor.slot().tag) { 547 return error.UnexpectedTag; 548 } 549 550 if (kv_pair.value_cursor.slot().value == baseline_value_cursor.slot().value) { 551 continue; 552 } 553 554 if (tag == .hash_map) { 555 const target_existing_cursor = try target.getCursor(kv_pair.hash) orelse return error.MergeConflict; 556 if (target_existing_cursor.slot().tag != .hash_map) { 557 return error.MergeConflict; 558 } 559 560 const target_child_cursor = try target.putCursor(kv_pair.hash); 561 const target_child = try DB.HashMap(.read_write).init(target_child_cursor); 562 const parent_child = try DB.HashMap(.read_only).init(kv_pair.value_cursor); 563 const baseline_child = try DB.HashMap(.read_only).init(baseline_value_cursor); 564 try mergeChangedMapEntries(DB, target_child, parent_child, baseline_child, false); 565 } else if (is_top_level) { 566 // the moment-index is a top-level key in the haxy moment 567 // and is not a map. we don't want to do any merge of this. 568 continue; 569 } else { 570 const target_value_cursor = try target.getCursor(kv_pair.hash) orelse return error.MergeConflict; 571 if (target_value_cursor.slot().value != baseline_value_cursor.slot().value) { 572 return error.MergeConflict; 573 } 574 575 try target.put(kv_pair.hash, .{ .slot = kv_pair.value_cursor.slot() }); 576 } 577 } 578 } 579 580 fn upsertField( 581 comptime DB: type, 582 comptime hash_kind: hash.HashKind, 583 map: DB.HashMap(.read_write), 584 comptime field_name: []const u8, 585 comptime Field: type, 586 value: Field, 587 ) !void { 588 const key = hash.hashInt(hash_kind, field_name); 589 590 switch (@typeInfo(Field)) { 591 .pointer => |pointer_info| { 592 if (pointer_info.size == .slice and pointer_info.child == u8) { 593 try upsertBytes(DB, hash_kind, map, key, value); 594 } else { 595 @compileError("unsupported upsert field type: " ++ @typeName(Field)); 596 } 597 }, 598 .array => |array_info| { 599 if (array_info.child == u8) { 600 try upsertBytes(DB, hash_kind, map, key, &value); 601 } else { 602 @compileError("unsupported upsert field type: " ++ @typeName(Field)); 603 } 604 }, 605 .int => |int_info| switch (int_info.signedness) { 606 .unsigned => { 607 if (try map.getCursor(key)) |value_cursor| { 608 if (try value_cursor.readUint() == value) { 609 return; 610 } 611 } 612 613 try map.put(key, .{ .uint = value }); 614 }, 615 .signed => { 616 if (try map.getCursor(key)) |value_cursor| { 617 if (try value_cursor.readInt() == value) { 618 return; 619 } 620 } 621 622 try map.put(key, .{ .int = value }); 623 }, 624 }, 625 .bool => { 626 const bytes = if (value) "true" else "false"; 627 if (try map.getCursor(key)) |value_cursor| { 628 var buffer: [5]u8 = undefined; 629 const existing = try value_cursor.readBytesObject(&buffer); 630 if (existing.format_tag) |format_tag| { 631 if (std.mem.eql(u8, &format_tag, "bl") and std.mem.eql(u8, existing.value, bytes)) { 632 return; 633 } 634 } 635 } 636 637 try map.put(key, .{ .bytes_object = .{ .value = bytes, .format_tag = "bl".* } }); 638 }, 639 else => @compileError("unsupported upsert field type: " ++ @typeName(Field)), 640 } 641 } 642 643 fn upsertBytes( 644 comptime DB: type, 645 comptime hash_kind: hash.HashKind, 646 map: DB.HashMap(.read_write), 647 key: hash.HashInt(hash_kind), 648 value: []const u8, 649 ) !void { 650 var existing_cursor_maybe = try map.getCursor(key); 651 if (existing_cursor_maybe) |*existing_cursor| { 652 if (try bytesEqual(DB, existing_cursor, value)) { 653 return; 654 } 655 } 656 657 var value_cursor = try map.putCursor(key); 658 var write_buffer: [1024]u8 = undefined; 659 var writer = try value_cursor.writer(&write_buffer); 660 try writer.interface.writeAll(value); 661 try writer.finish(); 662 } 663 664 fn bytesEqual( 665 comptime DB: type, 666 cursor: *DB.Cursor(.read_only), 667 value: []const u8, 668 ) !bool { 669 var read_buffer: [1024]u8 = undefined; 670 var reader = try cursor.reader(&read_buffer); 671 if (reader.size != value.len) { 672 return false; 673 } 674 675 var chunk_buffer: [1024]u8 = undefined; 676 var offset: usize = 0; 677 while (offset < value.len) { 678 const chunk_len = @min(chunk_buffer.len, value.len - offset); 679 try reader.interface.readSliceAll(chunk_buffer[0..chunk_len]); 680 if (!std.mem.eql(u8, chunk_buffer[0..chunk_len], value[offset .. offset + chunk_len])) { 681 return false; 682 } 683 offset += chunk_len; 684 } 685 686 return true; 687 } 688