Skip to content

Commit 3e2f162

Browse files
committed
Add support for lua.newMetatable(), lua.getMetatableRegistry(), lua.getMetaField()
1 parent cef0a4f commit 3e2f162

File tree

3 files changed

+82
-44
lines changed

3 files changed

+82
-44
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ you.
8686
| API | Support |
8787
|-----------------------------|---------------------------------------|
8888
| Lua C API (`lua_*`) | 🎉 100% coverage<sup>†</sup> (92/92) |
89-
| Auxilary Library (`luaL_*`) | 54% coverage (27/48) |
89+
| Auxilary Library (`luaL_*`) | 60% coverage (30/48) |
9090
| LuaJIT Extensions | *No plans to implement.* |
9191

9292
*†: Coroutine yield/resume is not yet part of the public `zig-luajit` Zig API, see [#6][ISSUE-6].*
@@ -246,13 +246,13 @@ The `zig-luajit` project has not yet reached the 1.0 release, the API is subject
246246
| `luaL_dofile` ||
247247
| `luaL_dostring` | ☑️ `lua.doString()` |
248248
| `luaL_error` | ☑️📢 `lua.raiseErrorFormat()` |
249-
| `luaL_getmetafield` ||
250-
| `luaL_getmetatable` ||
249+
| `luaL_getmetafield` | ☑️ `lua.getMetaField()` |
250+
| `luaL_getmetatable` | ☑️📢 `lua.getMetatableRegistry()` |
251251
| `luaL_gsub` | ☑️ `lua.gsub()` |
252252
| `luaL_loadbuffer` ||
253253
| `luaL_loadfile` ||
254254
| `luaL_loadstring` ||
255-
| `luaL_newmetatable` ||
255+
| `luaL_newmetatable` | ☑️ `lua.newMetatable()` |
256256
| `luaL_newstate` | 🆖 please use `Lua.init()` |
257257
| `luaL_openlibs` | ☑️ `lua.openLibs()` |
258258
| `luaL_optinteger` | ☑️📢 `lua.checkIntegerOptional()` |

src/lual_api.zig

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -89,23 +89,6 @@ pub fn callMeta(lua: *Lua, obj: i32, e: [*:0]const u8) bool;
8989
pub fn doFile(lua: *Lua, filename: [*:0]const u8) LuaError!void;
9090

9191

92-
93-
/// Pushes onto the stack the field `e` from the metatable of the object at index `obj`.
94-
/// If the object does not have a metatable, or if the metatable does not have this field,
95-
/// returns 0 and pushes nothing.
96-
///
97-
/// From: `int luaL_getmetafield(lua_State *L, int obj, const char *e);`
98-
/// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_getmetafield
99-
/// Stack Behavior: `[-0, +(0|1), m]`
100-
pub fn getMetaField(lua: *Lua, obj: i32, e: [:0]const u8) i32;
101-
102-
/// Pushes onto the stack the metatable associated with name tname in the registry.
103-
///
104-
/// From: `void luaL_getmetatable(lua_State *L, const char *tname);`
105-
/// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_getmetatable
106-
/// Stack Behavior: `[-0, +1, -]`
107-
pub fn getMetatable(lua: *Lua, name: [*:0]const u8) void;
108-
10992
/// Loads a buffer as a Lua chunk using lua_load to load the chunk in the buffer pointed to by buff with size sz.
11093
/// Returns the same results as lua_load. The name parameter is used for debug information and error messages.
11194
///
@@ -132,15 +115,6 @@ pub fn loadFile(lua: *Lua, filename: ?[:0]const u8) LuaError;
132115
/// Stack Behavior: `[-0, +1, m]`
133116
pub fn loadString(lua: *Lua, source: [*:0]const u8) LuaError;
134117

135-
/// If the registry already has the key tname, returns 0. Otherwise, creates a new table to be used as a
136-
/// metatable for userdata, adds it to the registry with key tname, and returns 1. In both cases pushes
137-
/// onto the stack the final value associated with tname in the registry.
138-
///
139-
/// From: `int luaL_newmetatable(lua_State *L, const char *tname);`
140-
/// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_newmetatable
141-
/// Stack Behavior: `[-0, +1, m]`
142-
pub fn newMetatable(lua: *Lua, tname: [*:0]const u8) i32;
143-
144118
/// Creates a new Lua state using the standard C realloc function for memory allocation and sets a default
145119
/// panic function that prints an error message to the standard error output in case of fatal errors.
146120
///

src/root.zig

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,19 +1115,6 @@ pub const Lua = opaque {
11151115
return c.lua_rawseti(asState(lua), index, n);
11161116
}
11171117

1118-
/// Pushes onto the stack the metatable of the value at the given acceptable index. If the index is not
1119-
/// valid, or if the value does not have a metatable, the function returns `false` and pushes nothing on
1120-
/// the stack.
1121-
///
1122-
/// From: `int lua_getmetatable(lua_State *L, int index);`
1123-
/// Refer to: https://www.lua.org/manual/5.1/manual.html#lua_getmetatable
1124-
/// Stack Behavior: `[-0, +(0|1), -]`
1125-
pub fn getMetatable(lua: *Lua, index: i32) bool {
1126-
lua.validateStackIndex(index);
1127-
1128-
return 1 == c.lua_getmetatable(asState(lua), index);
1129-
}
1130-
11311118
/// Pushes onto the stack the value `t[k]`, where `t` is the value at the given valid index. As in Lua, this function
11321119
/// may trigger a metamethod for the "index" event (see https://www.lua.org/manual/5.1/manual.html#2.8).
11331120
///
@@ -1142,7 +1129,7 @@ pub const Lua = opaque {
11421129
return lua.getType(-1);
11431130
}
11441131

1145-
/// Does the equivalent to `t[k] = v`, where `t` is the value at the given valid index and `v` is the value at the
1132+
/// Does the equivalent to `t[key] = v`, where `t` is the value at the given valid index and `v` is the value at the
11461133
/// top of the stack. This function pops the value from the stack. As in Lua, this function may trigger a
11471134
/// metamethod for the "newindex" event (see https://www.lua.org/manual/5.1/manual.html#2.8).
11481135
///
@@ -1176,6 +1163,19 @@ pub const Lua = opaque {
11761163

11771164
return c.lua_setglobal(asState(lua), asCString(name));
11781165
}
1166+
1167+
/// Creates a new table to be used as a metatable for userdata, adds it to the registry with key `tname`, and
1168+
/// returns `true`. If the registry already has the key `tname`, returns `false` instead.
1169+
///
1170+
/// In both cases, pushes onto the stack the final value associated with `tname` in the registry.
1171+
///
1172+
/// From: `int luaL_newmetatable(lua_State *L, const char *tname);`
1173+
/// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_newmetatable
1174+
/// Stack Behavior: `[-0, +1, m]`
1175+
pub fn newMetatable(lua: *Lua, tname: [:0]const u8) bool {
1176+
return 1 == c.luaL_newmetatable(asState(lua), tname.ptr);
1177+
}
1178+
11791179
/// Pops a table from the top of the stack and sets it as the metatable for the value at the
11801180
/// given acceptable index.
11811181
///
@@ -1190,6 +1190,43 @@ pub const Lua = opaque {
11901190
assert(1 == res);
11911191
}
11921192

1193+
/// Pushes onto the stack the metatable of the value at the given acceptable index. If the index is not
1194+
/// valid, or if the value does not have a metatable, the function returns `false` and pushes nothing on
1195+
/// the stack.
1196+
///
1197+
/// From: `int lua_getmetatable(lua_State *L, int index);`
1198+
/// Refer to: https://www.lua.org/manual/5.1/manual.html#lua_getmetatable
1199+
/// Stack Behavior: `[-0, +(0|1), -]`
1200+
pub fn getMetatable(lua: *Lua, index: i32) bool {
1201+
lua.validateStackIndex(index);
1202+
1203+
return 1 == c.lua_getmetatable(asState(lua), index);
1204+
}
1205+
1206+
/// Pushes onto the stack the metatable associated with name `name` in the registry.
1207+
///
1208+
/// Useful in combination with `newMetatable()`.
1209+
///
1210+
/// From: `void luaL_getmetatable(lua_State *L, const char *tname);`
1211+
/// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_getmetatable
1212+
/// Stack Behavior: `[-0, +1, -]`
1213+
pub fn getMetatableRegistry(lua: *Lua, name: [:0]const u8) void {
1214+
return c.luaL_getmetatable(asState(lua), name.ptr);
1215+
}
1216+
1217+
/// Pushes onto the stack the field `field_name` from the metatable of the object at index `index`. Returns `true`
1218+
/// when the metatable exists and the requested field has been pushed on the stack. Otherwise, if the object does
1219+
/// not have a metatable, or if the metatable does not have this field, returns `false` and pushes nothing.
1220+
///
1221+
/// From: `int luaL_getmetafield(lua_State *L, int obj, const char *e);`
1222+
/// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_getmetafield
1223+
/// Stack Behavior: `[-0, +(0|1), m]`
1224+
pub fn getMetaField(lua: *Lua, index: i32, field_name: [:0]const u8) bool {
1225+
lua.validateStackIndex(index);
1226+
1227+
return 1 == c.luaL_getmetafield(asState(lua), index, field_name.ptr);
1228+
}
1229+
11931230
/// Creates a new execution context within the given Lua instance, pushes it on the stack, and returns a `*Lua` pointer
11941231
/// that represents this new thread. Do not confuse Lua threads with operating-system threads. Lua supports coroutines
11951232
/// on all systems, even those that do not support threads.
@@ -4269,3 +4306,30 @@ test "gsub" {
42694306
try std.testing.expectEqualStrings(expected, try lua.toLString(-1));
42704307
try std.testing.expectEqualStrings(expected, actual);
42714308
}
4309+
4310+
test "metatables in the registry" {
4311+
const lua = try Lua.init(std.testing.allocator);
4312+
defer lua.deinit();
4313+
4314+
try std.testing.expect(lua.newMetatable("test"));
4315+
lua.pushInteger(42);
4316+
lua.setField(-2, "bar");
4317+
try std.testing.expect(!lua.newMetatable("test"));
4318+
4319+
try std.testing.expectEqual(2, lua.getTop());
4320+
try std.testing.expectEqual(lua.toPointer(-1), lua.toPointer(-2));
4321+
lua.pop(1);
4322+
4323+
lua.getMetatableRegistry("test");
4324+
try std.testing.expectEqual(2, lua.getTop());
4325+
try std.testing.expectEqual(lua.toPointer(-1), lua.toPointer(-2));
4326+
lua.pop(1);
4327+
4328+
lua.newTable();
4329+
lua.insert(-2);
4330+
lua.setMetatable(-2);
4331+
try std.testing.expectEqual(1, lua.getTop());
4332+
4333+
try std.testing.expect(lua.getMetaField(-1, "bar"));
4334+
try std.testing.expectEqual(42, try lua.toIntegerStrict(-1));
4335+
}

0 commit comments

Comments
 (0)