diff --git a/src/tests.zig b/src/tests.zig index a19a63b..f0abcaa 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -2574,6 +2574,57 @@ test "utils.List dynamic-item: offsets decrease" { try expectError(error.OffsetOrdering, L.sszDecode(&buf, &out, std.testing.allocator)); } +test "utils.List.clone copies backing storage independently" { + const L = utils.List([]const u8, 4); + var data = try L.init(std.testing.allocator); + defer data.deinit(); + try data.append("aa"); + try data.append("bb"); + + var cloned = try data.clone(std.testing.allocator); + defer cloned.deinit(); + + try expect(cloned.len() == data.len()); + try expect(cloned.inner.items.ptr != data.inner.items.ptr); + try expect(std.mem.eql(u8, (try cloned.get(0)), "aa")); + try expect((try cloned.get(0)).ptr == (try data.get(0)).ptr); +} + +test "utils.List.clone with variable-sized struct items" { + const L = utils.List(Pastry, 8); + var data = try L.init(std.testing.allocator); + defer data.deinit(); + try data.append(pastries[0]); + try data.append(pastries[1]); + + var cloned = try data.clone(std.testing.allocator); + defer cloned.deinit(); + + try expect(cloned.len() == 2); + try expect(cloned.inner.items.ptr != data.inner.items.ptr); + try expect((try cloned.get(0)).weight == pastries[0].weight); + try expect((try cloned.get(1)).weight == pastries[1].weight); + // Item-level []const u8 fields stay borrowed (shallow item copy). + try expect((try cloned.get(0)).name.ptr == pastries[0].name.ptr); + try expect((try cloned.get(1)).name.ptr == pastries[1].name.ptr); +} + +test "utils.Bitlist.clone copies backing storage independently" { + const B = utils.Bitlist(32); + var data = try B.init(std.testing.allocator); + defer data.deinit(); + try data.append(true); + try data.append(false); + try data.append(true); + + var cloned = try data.clone(std.testing.allocator); + defer cloned.deinit(); + + try expect(cloned.eql(&data)); + try cloned.set(0, false); + try expect((try data.get(0)) == true); +} + test { _ = @import("beacon_tests.zig"); } diff --git a/src/utils.zig b/src/utils.zig index 1f7d7c8..d0eb5ef 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -35,6 +35,14 @@ pub fn List(T: type, comptime N: usize) type { try serialize([]const Item, self.constSlice(), l, allocator); } + /// Clones this list's backing storage; item ownership matches normal List values. + pub fn clone(self: *const Self, allocator: Allocator) !Self { + var cloned = try Self.init(allocator); + errdefer cloned.deinit(); + try cloned.inner.appendSlice(allocator, self.inner.items); + return cloned; + } + pub fn isFixedSizeObject() bool { return false; } @@ -254,6 +262,15 @@ pub fn Bitlist(comptime N: usize) type { } } + /// Clones this bitlist's backing storage. + pub fn clone(self: *const Self, allocator: Allocator) !Self { + var cloned = try Self.init(allocator); + errdefer cloned.deinit(); + cloned.length = self.length; + try cloned.inner.appendSlice(allocator, self.inner.items); + return cloned; + } + pub fn sszDecode(serialized: []const u8, out: *Self, allocator: ?std.mem.Allocator) !void { const alloc = allocator orelse return error.AllocatorRequired; out.* = try init(alloc);