Skip to content

Commit dfe3b4d

Browse files
committed
fix: avoid std.meta.Tuple
This patch removes the use of `std.meta.Tuple` for compile-time metaprogramming. It's not clear to me that the convenience it brings makes the use of `std.meta` worth it. In particular, parsing the arguments list twice (once for `TypeOfWrap` and once in `wrap`) seems like an obvious area for improvement.
1 parent bf9fc6e commit dfe3b4d

File tree

1 file changed

+143
-164
lines changed

1 file changed

+143
-164
lines changed

src/lib.zig

Lines changed: 143 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -5157,21 +5157,30 @@ pub const Buffer = struct {
51575157

51585158
// Helper functions to make the zlua API easier to use
51595159

5160-
const Tuple = std.meta.Tuple;
5161-
51625160
fn TypeOfWrap(comptime function: anytype) type {
5163-
const Args = std.meta.ArgsTuple(@TypeOf(function));
5164-
return switch (Args) {
5165-
Tuple(&.{*Lua}) => CFn,
5166-
Tuple(&.{ *Lua, Event, *DebugInfo }) => CHookFn,
5167-
Tuple(&.{ *Lua, Status, Context }) => CContFn,
5168-
Tuple(&.{ *Lua, *anyopaque }) => CReaderFn,
5169-
Tuple(&.{*anyopaque}) => CUserdataDtorFn,
5170-
Tuple(&.{ *Lua, i32 }) => CInterruptCallbackFn,
5171-
Tuple(&.{[]const u8}) => CUserAtomCallbackFn,
5172-
Tuple(&.{ ?*anyopaque, []const u8, bool }) => CWarnFn,
5173-
Tuple(&.{ *Lua, []const u8, *anyopaque }) => CWriterFn,
5174-
else => @compileError("Unsupported function given to wrap '" ++ @typeName(@TypeOf(function)) ++ "'"),
5161+
const params = @typeInfo(@TypeOf(function)).@"fn".params;
5162+
if (params.len == 1) {
5163+
if (params[0].type.? == *Lua) return CFn;
5164+
if (params[0].type.? == []const u8) return CUserAtomCallbackFn;
5165+
if (params[0].type.? == *anyopaque) return CUserdataDtorFn;
5166+
}
5167+
if (params.len == 2) {
5168+
if (params[0].type.? == *Lua) {
5169+
if (params[1].type.? == i32) return CInterruptCallbackFn;
5170+
if (params[1].type.? == *anyopaque) return CReaderFn;
5171+
}
5172+
}
5173+
if (params.len == 3) {
5174+
if (params[0].type.? == ?*anyopaque and params[1].type.? == []const u8 and params[2].type.? == bool) return CWarnFn;
5175+
if (params[0].type.? == *Lua) {
5176+
if (params[1].type.? == Event and params[2].type.? == *DebugInfo) return CHookFn;
5177+
if (params[1].type.? == Status and params[2].type.? == Context) return CContFn;
5178+
if (params[1].type.? == []const u8 and params[2].type.? == *anyopaque) return CWriterFn;
5179+
}
5180+
}
5181+
return {
5182+
@compileLog(@TypeOf(function));
5183+
@compileError("Unsupported function given to wrap.");
51755184
};
51765185
}
51775186

@@ -5190,169 +5199,139 @@ fn TypeOfWrap(comptime function: anytype) type {
51905199
/// Functions that accept a `*Lua` pointer also support returning error unions. For example,
51915200
/// wrap also supports `fn (lua: *Lua) !i32` for a `CFn`.
51925201
pub fn wrap(comptime function: anytype) TypeOfWrap(function) {
5193-
const info = @typeInfo(@TypeOf(function));
5194-
if (info != .@"fn") {
5195-
@compileError("Wrap only accepts functions");
5196-
}
5197-
5198-
const has_error_union = @typeInfo(info.@"fn".return_type.?) == .error_union;
5199-
5200-
const Args = std.meta.ArgsTuple(@TypeOf(function));
5201-
switch (Args) {
5202-
// CFn
5203-
Tuple(&.{*Lua}) => {
5204-
return struct {
5205-
fn inner(state: ?*LuaState) callconv(.c) c_int {
5206-
// this is called by Lua, state should never be null
5207-
var lua: *Lua = @ptrCast(state.?);
5208-
if (has_error_union) {
5209-
return @call(.always_inline, function, .{lua}) catch |err| {
5210-
lua.raiseErrorStr(@errorName(err), .{});
5211-
};
5212-
} else {
5213-
return @call(.always_inline, function, .{lua});
5214-
}
5202+
const info = @typeInfo(@TypeOf(function)).@"fn";
5203+
5204+
const has_error_union = @typeInfo(info.return_type.?) == .error_union;
5205+
5206+
const Return = TypeOfWrap(function);
5207+
return switch (Return) {
5208+
CFn => struct {
5209+
fn inner(state: ?*LuaState) callconv(.c) c_int {
5210+
// this is called by Lua, state should never be null
5211+
var lua: *Lua = @ptrCast(state.?);
5212+
if (has_error_union) {
5213+
return @call(.always_inline, function, .{lua}) catch |err| {
5214+
lua.raiseErrorStr(@errorName(err), .{});
5215+
};
5216+
} else {
5217+
return @call(.always_inline, function, .{lua});
52155218
}
5216-
}.inner;
5217-
},
5218-
// CHookFn
5219-
Tuple(&.{ *Lua, Event, *DebugInfo }) => {
5220-
return struct {
5221-
fn inner(state: ?*LuaState, ar: ?*Debug) callconv(.c) void {
5222-
// this is called by Lua, state should never be null
5223-
var lua: *Lua = @ptrCast(state.?);
5224-
var debug_info: DebugInfo = .{
5225-
.current_line = if (ar.?.currentline == -1) null else ar.?.currentline,
5226-
.private = switch (lang) {
5227-
.lua51, .luajit => ar.?.i_ci,
5228-
else => @ptrCast(ar.?.i_ci),
5229-
},
5219+
}
5220+
}.inner,
5221+
CHookFn => struct {
5222+
fn inner(state: ?*LuaState, ar: ?*Debug) callconv(.c) void {
5223+
// this is called by Lua, state should never be null
5224+
var lua: *Lua = @ptrCast(state.?);
5225+
var debug_info: DebugInfo = .{
5226+
.current_line = if (ar.?.currentline == -1) null else ar.?.currentline,
5227+
.private = switch (lang) {
5228+
.lua51, .luajit => ar.?.i_ci,
5229+
else => @ptrCast(ar.?.i_ci),
5230+
},
5231+
};
5232+
if (has_error_union) {
5233+
@call(.always_inline, function, .{ lua, @as(Event, @enumFromInt(ar.?.event)), &debug_info }) catch |err| {
5234+
lua.raiseErrorStr(@errorName(err), .{});
52305235
};
5231-
if (has_error_union) {
5232-
@call(.always_inline, function, .{ lua, @as(Event, @enumFromInt(ar.?.event)), &debug_info }) catch |err| {
5233-
lua.raiseErrorStr(@errorName(err), .{});
5234-
};
5235-
} else {
5236-
@call(.always_inline, function, .{ lua, @as(Event, @enumFromInt(ar.?.event)), &debug_info });
5237-
}
5236+
} else {
5237+
@call(.always_inline, function, .{ lua, @as(Event, @enumFromInt(ar.?.event)), &debug_info });
52385238
}
5239-
}.inner;
5240-
},
5241-
// CContFn
5242-
Tuple(&.{ *Lua, Status, Context }) => {
5243-
return struct {
5244-
fn inner(state: ?*LuaState, status: c_int, ctx: Context) callconv(.c) c_int {
5245-
// this is called by Lua, state should never be null
5246-
var lua: *Lua = @ptrCast(state.?);
5247-
if (has_error_union) {
5248-
return @call(.always_inline, function, .{ lua, @as(Status, @enumFromInt(status)), ctx }) catch |err| {
5249-
lua.raiseErrorStr(@errorName(err), .{});
5250-
};
5251-
} else {
5252-
return @call(.always_inline, function, .{ lua, @as(Status, @enumFromInt(status)), ctx });
5253-
}
5239+
}
5240+
}.inner,
5241+
CContFn => struct {
5242+
fn inner(state: ?*LuaState, status: c_int, ctx: Context) callconv(.c) c_int {
5243+
// this is called by Lua, state should never be null
5244+
var lua: *Lua = @ptrCast(state.?);
5245+
if (has_error_union) {
5246+
return @call(.always_inline, function, .{ lua, @as(Status, @enumFromInt(status)), ctx }) catch |err| {
5247+
lua.raiseErrorStr(@errorName(err), .{});
5248+
};
5249+
} else {
5250+
return @call(.always_inline, function, .{ lua, @as(Status, @enumFromInt(status)), ctx });
52545251
}
5255-
}.inner;
5256-
},
5257-
// CReaderFn
5258-
Tuple(&.{ *Lua, *anyopaque }) => {
5259-
return struct {
5260-
fn inner(state: ?*LuaState, data: ?*anyopaque, size: [*c]usize) callconv(.c) [*c]const u8 {
5261-
// this is called by Lua, state should never be null
5262-
var lua: *Lua = @ptrCast(state.?);
5263-
if (has_error_union) {
5264-
const result = @call(.always_inline, function, .{ lua, data.? }) catch |err| {
5265-
lua.raiseErrorStr(@errorName(err), .{});
5266-
};
5267-
if (result) |buffer| {
5268-
size.* = buffer.len;
5269-
return buffer.ptr;
5270-
} else {
5271-
size.* = 0;
5272-
return null;
5273-
}
5252+
}
5253+
}.inner,
5254+
CReaderFn => struct {
5255+
fn inner(state: ?*LuaState, data: ?*anyopaque, size: [*c]usize) callconv(.c) [*c]const u8 {
5256+
// this is called by Lua, state should never be null
5257+
var lua: *Lua = @ptrCast(state.?);
5258+
if (has_error_union) {
5259+
const result = @call(.always_inline, function, .{ lua, data.? }) catch |err| {
5260+
lua.raiseErrorStr(@errorName(err), .{});
5261+
};
5262+
if (result) |buffer| {
5263+
size.* = buffer.len;
5264+
return buffer.ptr;
52745265
} else {
5275-
if (@call(.always_inline, function, .{ lua, data.? })) |buffer| {
5276-
size.* = buffer.len;
5277-
return buffer.ptr;
5278-
} else {
5279-
size.* = 0;
5280-
return null;
5281-
}
5266+
size.* = 0;
5267+
return null;
52825268
}
5283-
}
5284-
}.inner;
5285-
},
5286-
// CUserdataDtorFn
5287-
Tuple(&.{*anyopaque}) => {
5288-
return struct {
5289-
fn inner(userdata: *anyopaque) callconv(.c) void {
5290-
return @call(.always_inline, function, .{userdata});
5291-
}
5292-
}.inner;
5293-
},
5294-
// CInterruptCallbackFn
5295-
Tuple(&.{ *Lua, i32 }) => {
5296-
return struct {
5297-
fn inner(state: ?*LuaState, gc: c_int) callconv(.c) void {
5298-
// this is called by Lua, state should never be null
5299-
var lua: *Lua = @ptrCast(state.?);
5300-
if (has_error_union) {
5301-
@call(.always_inline, function, .{ lua, gc }) catch |err| {
5302-
lua.raiseErrorStr(@errorName(err), .{});
5303-
};
5269+
} else {
5270+
if (@call(.always_inline, function, .{ lua, data.? })) |buffer| {
5271+
size.* = buffer.len;
5272+
return buffer.ptr;
53045273
} else {
5305-
@call(.always_inline, function, .{ lua, gc });
5274+
size.* = 0;
5275+
return null;
53065276
}
53075277
}
5308-
}.inner;
5309-
},
5310-
// CUserAtomCallbackFn
5311-
Tuple(&.{[]const u8}) => {
5312-
return struct {
5313-
fn inner(str: [*c]const u8, len: usize) callconv(.c) i16 {
5314-
if (str) |s| {
5315-
const buf = s[0..len];
5316-
return @call(.always_inline, function, .{buf});
5317-
}
5318-
return -1;
5278+
}
5279+
}.inner,
5280+
CUserdataDtorFn => struct {
5281+
fn inner(userdata: *anyopaque) callconv(.c) void {
5282+
return @call(.always_inline, function, .{userdata});
5283+
}
5284+
}.inner,
5285+
CInterruptCallbackFn => struct {
5286+
fn inner(state: ?*LuaState, gc: c_int) callconv(.c) void {
5287+
// this is called by Lua, state should never be null
5288+
var lua: *Lua = @ptrCast(state.?);
5289+
if (has_error_union) {
5290+
@call(.always_inline, function, .{ lua, gc }) catch |err| {
5291+
lua.raiseErrorStr(@errorName(err), .{});
5292+
};
5293+
} else {
5294+
@call(.always_inline, function, .{ lua, gc });
53195295
}
5320-
}.inner;
5321-
},
5322-
// CWarnFn
5323-
Tuple(&.{ ?*anyopaque, []const u8, bool }) => {
5324-
return struct {
5325-
fn inner(data: ?*anyopaque, msg: [*c]const u8, to_cont: c_int) callconv(.c) void {
5326-
// warning messages emitted from Lua should be null-terminated for display
5327-
const message = std.mem.span(@as([*:0]const u8, @ptrCast(msg)));
5328-
@call(.always_inline, function, .{ data, message, to_cont != 0 });
5296+
}
5297+
}.inner,
5298+
CUserAtomCallbackFn => struct {
5299+
fn inner(str: [*c]const u8, len: usize) callconv(.c) i16 {
5300+
if (str) |s| {
5301+
const buf = s[0..len];
5302+
return @call(.always_inline, function, .{buf});
53295303
}
5330-
}.inner;
5331-
},
5332-
// CWriterFn
5333-
Tuple(&.{ *Lua, []const u8, *anyopaque }) => {
5334-
return struct {
5335-
fn inner(state: ?*LuaState, buf: ?*const anyopaque, size: usize, data: ?*anyopaque) callconv(.c) c_int {
5336-
// this is called by Lua, state should never be null
5337-
var lua: *Lua = @ptrCast(state.?);
5338-
const buffer = @as([*]const u8, @ptrCast(buf))[0..size];
5339-
5340-
const result = if (has_error_union) blk: {
5341-
break :blk @call(.always_inline, function, .{ lua, buffer, data.? }) catch |err| {
5342-
lua.raiseErrorStr(@errorName(err), .{});
5343-
};
5344-
} else blk: {
5345-
break :blk @call(.always_inline, function, .{ lua, buffer, data.? });
5304+
return -1;
5305+
}
5306+
}.inner,
5307+
CWarnFn => struct {
5308+
fn inner(data: ?*anyopaque, msg: [*c]const u8, to_cont: c_int) callconv(.c) void {
5309+
// warning messages emitted from Lua should be null-terminated for display
5310+
const message = std.mem.span(@as([*:0]const u8, @ptrCast(msg)));
5311+
@call(.always_inline, function, .{ data, message, to_cont != 0 });
5312+
}
5313+
}.inner,
5314+
CWriterFn => struct {
5315+
fn inner(state: ?*LuaState, buf: ?*const anyopaque, size: usize, data: ?*anyopaque) callconv(.c) c_int {
5316+
// this is called by Lua, state should never be null
5317+
var lua: *Lua = @ptrCast(state.?);
5318+
const buffer = @as([*]const u8, @ptrCast(buf))[0..size];
5319+
5320+
const result = if (has_error_union) blk: {
5321+
break :blk @call(.always_inline, function, .{ lua, buffer, data.? }) catch |err| {
5322+
lua.raiseErrorStr(@errorName(err), .{});
53465323
};
5324+
} else blk: {
5325+
break :blk @call(.always_inline, function, .{ lua, buffer, data.? });
5326+
};
53475327

5348-
// it makes more sense for the inner writer function to return false for failure,
5349-
// so negate the result here
5350-
return @intFromBool(!result);
5351-
}
5352-
}.inner;
5353-
},
5354-
else => @compileError("Unsupported function given to wrap '" ++ @typeName(@TypeOf(function)) ++ "'"),
5355-
}
5328+
// it makes more sense for the inner writer function to return false for failure,
5329+
// so negate the result here
5330+
return @intFromBool(!result);
5331+
}
5332+
}.inner,
5333+
else => unreachable,
5334+
};
53565335
}
53575336

53585337
/// Zig wrapper for Luau lua_CompileOptions that uses the same defaults as Luau if

0 commit comments

Comments
 (0)