Skip to content

Commit 67d8fa1

Browse files
committed
Add Table.clone
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
1 parent d9874e1 commit 67d8fa1

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
1313
- `Lua.createMetaTable()` for flexible metatable creation without global registration
1414
- `Table.setMetaTable()` and `Table.getMetaTable()` for metatable attachment and retrieval
1515
- `Table.clear()` method to remove all entries from a table
16+
- `Table.clone()` method to create a shallow copy of a table
1617

1718
### Changed
1819
- **BREAKING**: Table iteration API now uses standard Zig iterator pattern (`iterator.next()`)

src/lua.zig

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,45 @@ pub const Lua = struct {
860860
self.state().pop(1); // Pop table
861861
}
862862

863+
/// Creates a shallow copy of the table.
864+
///
865+
/// Returns a new table with the same key-value pairs as the original.
866+
/// This is a shallow copy: primitive values (numbers, strings, booleans) are
867+
/// duplicated, but reference types (tables, functions, userdata) are shared
868+
/// between the original and cloned table.
869+
///
870+
/// The clone inherits the original table's metatable reference (not cloned).
871+
/// The readonly and safeenv flags are not copied to the clone.
872+
///
873+
/// Examples:
874+
/// ```zig
875+
/// const original = lua.createTable(.{});
876+
/// defer original.deinit();
877+
/// try original.set("name", "Alice");
878+
///
879+
/// const cloned = try original.clone();
880+
/// defer cloned.deinit();
881+
///
882+
/// // Clone has same values
883+
/// const name = try cloned.get("name", []const u8);
884+
/// try expect(std.mem.eql(u8, name.?, "Alice"));
885+
/// ```
886+
///
887+
/// Returns: `Table` - A new table containing a shallow copy of the original
888+
/// Errors: `Error.OutOfMemory` if allocation fails
889+
pub fn clone(self: Table) !Table {
890+
try self.ref.lua.checkStack(2);
891+
892+
stack.push(self.ref.lua, self.ref); // Push table ref
893+
self.state().cloneTable(-1); // Clone table, pushes clone on stack
894+
895+
// Create a reference to the cloned table on the stack
896+
const cloned_ref = Ref.init(self.ref.lua, -1);
897+
self.state().pop(2); // Pop both original and cloned tables
898+
899+
return Table{ .ref = cloned_ref };
900+
}
901+
863902
/// Entry representing a key-value pair from table iteration.
864903
/// Resources are automatically managed when using the `Iterator` type.
865904
pub const Entry = struct {

src/tests.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,22 @@ test "table clear" {
13801380
try expect(name == null);
13811381
}
13821382

1383+
test "table clone" {
1384+
const lua = try Lua.init(&std.testing.allocator);
1385+
defer lua.deinit();
1386+
1387+
const original = lua.createTable(.{});
1388+
defer original.deinit();
1389+
try original.set("name", "Alice");
1390+
1391+
const cloned = try original.clone();
1392+
defer cloned.deinit();
1393+
1394+
// Clone has same values
1395+
const name = try cloned.get("name", []const u8);
1396+
try expect(std.mem.eql(u8, name.?, "Alice"));
1397+
}
1398+
13831399
fn closureAdd5(n: i32, x: i32) i32 {
13841400
return x + n;
13851401
}

0 commit comments

Comments
 (0)