Zig 0.14 compatibility

This commit is contained in:
Karl Seguin
2025-03-06 23:00:13 +08:00
committed by Pierre Tachoire
parent 17d3d620ff
commit 21c9dde858
26 changed files with 78 additions and 197 deletions

View File

@@ -5,7 +5,7 @@ inputs:
zig:
description: 'Zig version to install'
required: false
default: '0.13.0'
default: '0.14.0'
arch:
description: 'CPU arch used to select the v8 lib'
required: false

View File

@@ -1,7 +1,7 @@
name: zig-fmt
env:
ZIG_VERSION: 0.13.0
ZIG_VERSION: 0.14.0
on:
pull_request:

2
.gitmodules vendored
View File

@@ -1,6 +1,7 @@
[submodule "vendor/zig-js-runtime"]
path = vendor/zig-js-runtime
url = https://github.com/lightpanda-io/zig-js-runtime.git/
branch = zig-0.14
[submodule "vendor/netsurf/libwapcaplet"]
path = vendor/netsurf/libwapcaplet
url = https://github.com/lightpanda-io/libwapcaplet.git/
@@ -28,3 +29,4 @@
[submodule "vendor/zig-async-io"]
path = vendor/zig-async-io
url = https://github.com/lightpanda-io/zig-async-io.git/
branch = zig-0.14

View File

@@ -1,7 +1,7 @@
FROM ubuntu:24.04
ARG MINISIG=0.12
ARG ZIG=0.13.0
ARG ZIG=0.14.0
ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U
ARG ARCH=x86_64
ARG V8=11.1.134

View File

@@ -140,7 +140,7 @@ You can also follow the progress of our Javascript support in our dedicated [zig
### Prerequisites
Lightpanda is written with [Zig](https://ziglang.org/) `0.13.0`. You have to
Lightpanda is written with [Zig](https://ziglang.org/) `0.14.0`. You have to
install it with the right version in order to build the project.
Lightpanda also depends on

View File

@@ -108,7 +108,7 @@ pub fn build(b: *std.Build) !void {
// compile
const tests = b.addTest(.{
.root_source_file = b.path("src/main_tests.zig"),
.test_runner = b.path("src/main_tests.zig"),
.test_runner = .{ .path = b.path("src/main_tests.zig"), .mode = .simple },
.target = target,
.optimize = mode,
});
@@ -134,7 +134,7 @@ pub fn build(b: *std.Build) !void {
// compile
const unit_tests = b.addTest(.{
.root_source_file = b.path("src/unit_tests.zig"),
.test_runner = b.path("src/unit_tests.zig"),
.test_runner = .{ .path = b.path("src/unit_tests.zig"), .mode = .simple },
.target = target,
.optimize = mode,
});
@@ -195,7 +195,7 @@ fn common(
step.root_module.addImport("asyncio", asyncio);
const tlsmod = b.addModule("tls", .{
.root_source_file = b.path("vendor/tls.zig/src/main.zig"),
.root_source_file = b.path("vendor/tls.zig/src/root.zig"),
});
step.root_module.addImport("tls", tlsmod);
}

View File

@@ -156,16 +156,16 @@ pub const Session = struct {
const ContextT = @TypeOf(ctx);
const InspectorContainer = switch (@typeInfo(ContextT)) {
.Struct => ContextT,
.Pointer => |ptr| ptr.child,
.Void => NoopInspector,
.@"struct" => ContextT,
.pointer => |ptr| ptr.child,
.void => NoopInspector,
else => @compileError("invalid context type"),
};
// const ctx_opaque = @as(*anyopaque, @ptrCast(ctx));
self.inspector = try jsruntime.Inspector.init(
arena,
self.env, // TODO: change to 'env' when https://github.com/lightpanda-io/zig-js-runtime/pull/285 lands
&self.env,
if (@TypeOf(ctx) == void) @constCast(@ptrCast(&{})) else ctx,
InspectorContainer.onInspectorResponse,
InspectorContainer.onInspectorEvent,
@@ -231,7 +231,7 @@ pub const Session = struct {
// load polyfills
// TODO: change to 'env' when https://github.com/lightpanda-io/zig-js-runtime/pull/285 lands
try polyfill.load(self.arena.allocator(), self.env);
try polyfill.load(self.arena.allocator(), &self.env);
// inspector
self.contextCreated(page, aux_data);
@@ -264,7 +264,7 @@ pub const Session = struct {
fn contextCreated(self: *Session, page: *Page, aux_data: ?[]const u8) void {
log.debug("inspector context created", .{});
self.inspector.contextCreated(self.env, "", page.origin orelse "://", aux_data);
self.inspector.contextCreated(&self.env, "", page.origin orelse "://", aux_data);
}
};
@@ -316,7 +316,7 @@ pub const Page = struct {
pub fn wait(self: *Page) !void {
// try catch
var try_catch: jsruntime.TryCatch = undefined;
try_catch.init(self.session.env);
try_catch.init(&self.session.env);
defer try_catch.deinit();
self.session.env.wait() catch |err| {
@@ -324,7 +324,7 @@ pub const Page = struct {
if (err == error.EnvNotStarted) return;
const arena = self.arena;
if (try try_catch.err(arena, self.session.env)) |msg| {
if (try try_catch.err(arena, &self.session.env)) |msg| {
defer arena.free(msg);
log.info("wait error: {s}", .{msg});
return;
@@ -591,9 +591,7 @@ pub const Page = struct {
// TODO handle charset attribute
const opt_text = try parser.nodeTextContent(parser.elementToNode(s.element));
if (opt_text) |text| {
// TODO: change to &self.session.env when
// https://github.com/lightpanda-io/zig-js-runtime/pull/285 lands
try s.eval(self.arena, self.session.env, text);
try s.eval(self.arena, &self.session.env, text);
return;
}
@@ -656,11 +654,8 @@ pub const Page = struct {
// received.
fn fetchScript(self: *const Page, s: *const Script) !void {
const arena = self.arena;
const body = try self.fetchData(arena, s.src, null);
// TODO: change to &self.session.env when
// https://github.com/lightpanda-io/zig-js-runtime/pull/285 lands
try s.eval(arena, self.session.env, body);
try s.eval(arena, &self.session.env, body);
}
const Script = struct {
@@ -683,9 +678,8 @@ pub const Page = struct {
return .{
.element = e,
.kind = kind(try parser.elementGetAttribute(e, "type")),
.kind = parseKind(try parser.elementGetAttribute(e, "type")),
.is_async = try parser.elementGetAttribute(e, "async") != null,
.src = try parser.elementGetAttribute(e, "src") orelse "inline",
};
}
@@ -695,7 +689,7 @@ pub const Page = struct {
// > type indicates that the script is a "classic script", containing
// > JavaScript code.
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attribute_is_not_set_default_an_empty_string_or_a_javascript_mime_type
fn kind(stype: ?[]const u8) Kind {
fn parseKind(stype: ?[]const u8) Kind {
if (stype == null or stype.?.len == 0) return .javascript;
if (std.mem.eql(u8, stype.?, "application/javascript")) return .javascript;
if (std.mem.eql(u8, stype.?, "module")) return .module;
@@ -703,7 +697,7 @@ pub const Page = struct {
return .unknown;
}
fn eval(self: Script, arena: Allocator, env: Env, body: []const u8) !void {
fn eval(self: Script, arena: Allocator, env: *const Env, body: []const u8) !void {
var try_catch: jsruntime.TryCatch = undefined;
try_catch.init(env);
defer try_catch.deinit();

View File

@@ -245,7 +245,7 @@ pub const Mime = struct {
const bit_len = @bitSizeOf(@TypeOf(target.*)) - 8;
const byte_len = bit_len / 8;
const T = @Type(.{ .Int = .{
const T = @Type(.{ .int = .{
.bits = bit_len,
.signedness = .unsigned,
} });

View File

@@ -454,7 +454,7 @@ pub fn Command(comptime CDP_T: type, comptime Sender: type) type {
pub fn sendResult(self: *Self, result: anytype, opts: SendResultOpts) !void {
return self.sender.sendJSON(.{
.id = self.input.id,
.result = if (comptime @typeInfo(@TypeOf(result)) == .Null) struct {}{} else result,
.result = if (comptime @typeInfo(@TypeOf(result)) == .null) struct {}{} else result,
.sessionId = if (opts.include_session_id) self.input.session_id else null,
});
}
@@ -466,7 +466,7 @@ pub fn Command(comptime CDP_T: type, comptime Sender: type) type {
// Events ALWAYS go to the client. self.sender should not be used
return self.cdp.sendJSON(.{
.method = method,
.params = if (comptime @typeInfo(@TypeOf(p)) == .Null) struct {}{} else p,
.params = if (comptime @typeInfo(@TypeOf(p)) == .null) struct {}{} else p,
.sessionId = opts.session_id,
});
}

View File

@@ -174,8 +174,8 @@ const TestContext = struct {
pub fn processMessage(self: *TestContext, msg: anytype) !void {
var json_message: []const u8 = undefined;
if (@typeInfo(@TypeOf(msg)) != .Pointer) {
json_message = try json.stringifyAlloc(self.arena.allocator(), msg, .{});
if (@typeInfo(@TypeOf(msg)) != .pointer) {
json_message = try std.json.stringifyAlloc(self.arena.allocator(), msg, .{});
} else {
// assume this is a string we want to send as-is, if it isn't, we'll
// get a compile error, so no big deal.
@@ -196,7 +196,7 @@ const TestContext = struct {
pub fn expectSentResult(self: *TestContext, expected: anytype, opts: ExpectResultOpts) !void {
const expected_result = .{
.id = opts.id,
.result = if (comptime @typeInfo(@TypeOf(expected)) == .Null) struct {}{} else expected,
.result = if (comptime @typeInfo(@TypeOf(expected)) == .null) struct {}{} else expected,
.sessionId = opts.session_id,
};
@@ -210,7 +210,7 @@ const TestContext = struct {
pub fn expectSentEvent(self: *TestContext, method: []const u8, params: anytype, opts: ExpectEventOpts) !void {
const expected_event = .{
.method = method,
.params = if (comptime @typeInfo(@TypeOf(params)) == .Null) struct {}{} else params,
.params = if (comptime @typeInfo(@TypeOf(params)) == .null) struct {}{} else params,
.sessionId = opts.session_id,
};
@@ -323,96 +323,3 @@ fn compareJsonValues(a: std.json.Value, b: std.json.Value) bool {
},
}
}
// fn compareAnyToJsonValue(expected: anytype, actual: json.Value) bool {
// switch (@typeInfo(@TypeOf(expected))) {
// .Optional => {
// if (expected) |e| {
// return compareAnyToJsonValue(e, actual);
// }
// return actual == .null;
// },
// .Int, .ComptimeInt => {
// if (actual != .integer) {
// return false;
// }
// return expected == actual.integer;
// },
// .Float, .ComptimeFloat => {
// if (actual != .float) {
// return false;
// }
// return expected == actual.float;
// },
// .Bool => {
// if (actual != .bool) {
// return false;
// }
// return expected == actual.bool;
// },
// .Pointer => |ptr| switch (ptr.size) {
// .One => switch (@typeInfo(ptr.child)) {
// .Struct => return compareAnyToJsonValue(expected.*, actual),
// .Array => |arr| if (arr.child == u8) {
// if (actual != .string) {
// return false;
// }
// return std.mem.eql(u8, expected, actual.string);
// },
// else => {},
// },
// .Slice => switch (ptr.child) {
// u8 => {
// if (actual != .string) {
// return false;
// }
// return std.mem.eql(u8, expected, actual.string);
// },
// else => {},
// },
// else => {},
// },
// .Struct => |s| {
// if (s.is_tuple) {
// // how an array might look in an anytype
// if (actual != .array) {
// return false;
// }
// if (s.fields.len != actual.array.items.len) {
// return false;
// }
// inline for (s.fields, 0..) |f, i| {
// const e = @field(expected, f.name);
// if (compareAnyToJsonValue(e, actual.array.items[i]) == false) {
// return false;
// }
// }
// return true;
// }
// if (s.fields.len == 0) {
// return (actual == .array and actual.array.items.len == 0);
// }
// if (actual != .object) {
// return false;
// }
// inline for (s.fields) |f| {
// const e = @field(expected, f.name);
// if (actual.object.get(f.name)) |a| {
// if (compareAnyToJsonValue(e, a) == false) {
// return false;
// }
// } else if (@typeInfo(f.type) != .Optional or e != null) {
// // We don't JSON serialize nulls. So if we're expecting
// // a null, that should show up as a missing field.
// return false;
// }
// }
// return true;
// },
// else => {},
// }
// @compileError("Can't compare " ++ @typeName(@TypeOf(expected)));
// }

View File

@@ -63,7 +63,7 @@ pub fn Union(interfaces: anytype) type {
.decls = &.{},
.is_exhaustive = true,
};
const enum_T = @Type(.{ .Enum = enum_info });
const enum_T = @Type(.{ .@"enum" = enum_info });
// third iteration to generate union type
var union_fields: [fields.len]Type.UnionField = undefined;
@@ -79,7 +79,7 @@ pub fn Union(interfaces: anytype) type {
};
}
return @Type(.{ .Union = .{
return @Type(.{ .@"union" = .{
.layout = .auto,
.tag_type = enum_T,
.fields = &union_fields,
@@ -115,12 +115,12 @@ pub fn Tuple(args: anytype) type {
// has to be true in order to properly capture the default value
.is_comptime = true,
.alignment = @alignOf(type),
.default_value = @ptrCast(&interfaces[i]),
.default_value_ptr = @ptrCast(&interfaces[i]),
};
field_index += 1;
}
return @Type(.{ .Struct = .{
return @Type(.{ .@"struct" = .{
.layout = .auto,
.fields = &fields,
.decls = &.{},
@@ -130,7 +130,7 @@ pub fn Tuple(args: anytype) type {
fn countInterfaces(args: anytype, count: usize) usize {
var new_count = count;
for (@typeInfo(@TypeOf(args)).Struct.fields) |f| {
for (@typeInfo(@TypeOf(args)).@"struct".fields) |f| {
const member = @field(args, f.name);
if (@TypeOf(member) == type) {
new_count += 1;
@@ -143,7 +143,7 @@ fn countInterfaces(args: anytype, count: usize) usize {
fn flattenInterfaces(args: anytype, interfaces: []type, index: usize) usize {
var new_index = index;
for (@typeInfo(@TypeOf(args)).Struct.fields) |f| {
for (@typeInfo(@TypeOf(args)).@"struct".fields) |f| {
const member = @field(args, f.name);
if (@TypeOf(member) == type) {
interfaces[new_index] = member;
@@ -186,7 +186,7 @@ test "generate.Union" {
};
const value = Union(.{ Astruct, Bstruct, .{Cstruct} });
const ti = @typeInfo(value).Union;
const ti = @typeInfo(value).@"union";
try std.testing.expectEqual(3, ti.fields.len);
try std.testing.expectEqualStrings("*generate.test.generate.Union.Astruct.Other", @typeName(ti.fields[0].type));
try std.testing.expectEqualStrings(ti.fields[0].name, "Astruct");
@@ -209,7 +209,7 @@ test "generate.Tuple" {
{
const tuple = Tuple(.{ Astruct, Bstruct }){};
const ti = @typeInfo(@TypeOf(tuple)).Struct;
const ti = @typeInfo(@TypeOf(tuple)).@"struct";
try std.testing.expectEqual(true, ti.is_tuple);
try std.testing.expectEqual(2, ti.fields.len);
try std.testing.expectEqual(Astruct, tuple.@"0");
@@ -219,7 +219,7 @@ test "generate.Tuple" {
{
// dedupe
const tuple = Tuple(.{ Cstruct, Astruct, .{Astruct}, Bstruct, .{ Astruct, .{ Astruct, Bstruct } } }){};
const ti = @typeInfo(@TypeOf(tuple)).Struct;
const ti = @typeInfo(@TypeOf(tuple)).@"struct";
try std.testing.expectEqual(true, ti.is_tuple);
try std.testing.expectEqual(3, ti.fields.len);
try std.testing.expectEqual(Cstruct, tuple.@"0");

View File

@@ -1358,7 +1358,7 @@ pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connec
conn.data.tls_client.* = tls23.client(stream, .{
.host = host,
.root_ca = client.ca_bundle,
.root_ca = .{ .bundle = client.ca_bundle },
}) catch return error.TlsInitializationFailed;
}

View File

@@ -27,7 +27,7 @@ pub fn Incrementing(comptime T: type, comptime prefix: []const u8) type {
break :blk b;
};
const PrefixIntType = @Type(.{ .Int = .{
const PrefixIntType = @Type(.{ .int = .{
.bits = NUMERIC_START * 8,
.signedness = .unsigned,
} });

View File

@@ -151,7 +151,7 @@ fn LogT(comptime Out: type, comptime enhanced_readability: bool) type {
buffer.appendSliceAssumeCapacity(inject);
}
inline for (@typeInfo(@TypeOf(data)).Struct.fields) |f| {
inline for (@typeInfo(@TypeOf(data)).@"struct".fields) |f| {
// + 2 for the leading space and the equal sign
// + 5 to save space for null/false/true common values
const key_len = f.name.len + 7;
@@ -179,30 +179,30 @@ fn LogT(comptime Out: type, comptime enhanced_readability: bool) type {
fn writeValue(allocator: Allocator, buffer: *std.ArrayListUnmanaged(u8), value: anytype) !void {
const T = @TypeOf(value);
switch (@typeInfo(T)) {
.Optional => {
.optional => {
if (value) |v| {
return writeValue(allocator, buffer, v);
}
// in _log, we reserved space for a value of up to 5 bytes.
return buffer.appendSliceAssumeCapacity("null");
},
.ComptimeInt, .Int, .ComptimeFloat, .Float => {
.comptime_int, .int, .comptime_float, .float => {
return std.fmt.format(buffer.writer(allocator), "{d}", .{value});
},
.Bool => {
.bool => {
// in _log, we reserved space for a value of up to 5 bytes.
return buffer.appendSliceAssumeCapacity(if (value) "true" else "false");
},
.ErrorSet => return buffer.appendSlice(allocator, @errorName(value)),
.Enum => return buffer.appendSlice(allocator, @tagName(value)),
.Array => return writeValue(allocator, buffer, &value),
.Pointer => |ptr| switch (ptr.size) {
.Slice => switch (ptr.child) {
.error_set => return buffer.appendSlice(allocator, @errorName(value)),
.@"enum" => return buffer.appendSlice(allocator, @tagName(value)),
.array => return writeValue(allocator, buffer, &value),
.pointer => |ptr| switch (ptr.size) {
.slice => switch (ptr.child) {
u8 => return writeString(allocator, buffer, value),
else => {},
},
.One => switch (@typeInfo(ptr.child)) {
.Array => |arr| if (arr.child == u8) {
.one => switch (@typeInfo(ptr.child)) {
.array => |arr| if (arr.child == u8) {
return writeString(allocator, buffer, value);
},
else => return false,

View File

@@ -35,7 +35,7 @@ const version = @import("build_info").git_commit;
const log = std.log.scoped(.cli);
pub const std_options = .{
pub const std_options = std.Options{
// Set the log level to info
.log_level = .debug,
@@ -344,7 +344,7 @@ fn parseFetchArgs(
var verbose: bool = builtin.mode == .Debug; // In debug mode, force verbose.
fn logFn(
comptime level: std.log.Level,
comptime scope: @Type(.EnumLiteral),
comptime scope: @Type(.enum_literal),
comptime format: []const u8,
args: anytype,
) void {

View File

@@ -260,7 +260,7 @@ pub const Tag = enum(u8) {
pub fn all() []Tag {
comptime {
const info = @typeInfo(Tag).Enum;
const info = @typeInfo(Tag).@"enum";
var l: [info.fields.len]Tag = undefined;
for (info.fields, 0..) |field, i| {
l[i] = @as(Tag, @enumFromInt(field.value));
@@ -804,7 +804,7 @@ pub fn eventTargetDispatchEvent(et: *EventTarget, event: *Event) !bool {
pub fn eventTargetTBaseFieldName(comptime T: type) ?[]const u8 {
std.debug.assert(@inComptime());
switch (@typeInfo(T)) {
.Struct => |ti| {
.@"struct" => |ti| {
for (ti.fields) |f| {
if (f.type == EventTargetTBase) return f.name;
}

View File

@@ -20,7 +20,7 @@ pub fn testExecFn(
alloc: std.mem.Allocator,
js_env: *jsruntime.Env,
) anyerror!void {
try @import("polyfill.zig").load(alloc, js_env.*);
try @import("polyfill.zig").load(alloc, js_env);
var fetch = [_]Case{
.{

View File

@@ -33,7 +33,7 @@ const modules = [_]struct {
.{ .name = "polyfill-fetch", .source = @import("fetch.zig").source },
};
pub fn load(alloc: std.mem.Allocator, env: Env) !void {
pub fn load(alloc: std.mem.Allocator, env: *const Env) !void {
var try_catch: jsruntime.TryCatch = undefined;
try_catch.init(env);
defer try_catch.deinit();

View File

@@ -57,13 +57,6 @@ const Server = struct {
listener: posix.socket_t,
timeout: u64,
// A memory poor for our Clients. Because we only allow 1 client to be
// connected at a time, and because of the way we accept, we don't need
// a lock for this, since the creation of a new client cannot happen at the
// same time as the destruction of a client.
client_pool: std.heap.MemoryPool(Client),
client_pool_lock: std.Thread.Mutex = .{},
// I/O fields
accept_completion: Completion,
@@ -71,7 +64,7 @@ const Server = struct {
json_version_response: []const u8,
fn deinit(self: *Server) void {
self.client_pool.deinit();
_ = self;
}
fn queueAccept(self: *Server) void {
@@ -102,28 +95,14 @@ const Server = struct {
result: AcceptError!posix.socket_t,
) !void {
const socket = try result;
const client = blk: {
self.client_pool_lock.lock();
defer self.client_pool_lock.unlock();
break :blk try self.client_pool.create();
};
errdefer {
self.client_pool_lock.lock();
self.client_pool.destroy(client);
self.client_pool_lock.unlock();
}
const client = try self.allocator.create(Client);
client.* = Client.init(socket, self);
client.start();
log.info("client connected", .{});
}
fn releaseClient(self: *Server, client: *Client) void {
self.client_pool_lock.lock();
self.client_pool.destroy(client);
self.client_pool_lock.unlock();
self.allocator.destroy(client);
}
};
@@ -1053,7 +1032,6 @@ pub fn run(
.allocator = allocator,
.accept_completion = undefined,
.json_version_response = json_version_response,
.client_pool = std.heap.MemoryPool(Client).init(allocator),
};
defer server.deinit();
@@ -1488,8 +1466,8 @@ fn createTestClient() !TestClient {
const stream = try std.net.tcpConnectToAddress(address);
const timeout = std.mem.toBytes(posix.timeval{
.tv_sec = 2,
.tv_usec = 0,
.sec = 2,
.usec = 0,
});
try posix.setsockopt(stream.handle, posix.SOL.SOCKET, posix.SO.RCVTIMEO, &timeout);
try posix.setsockopt(stream.handle, posix.SOL.SOCKET, posix.SO.SNDTIMEO, &timeout);

View File

@@ -922,7 +922,7 @@ fn expectAttribute(expected: anytype, url: ?[]const u8, set_cookie: []const u8)
var cookie = try Cookie.parse(testing.allocator, uri, set_cookie);
defer cookie.deinit();
inline for (@typeInfo(@TypeOf(expected)).Struct.fields) |f| {
inline for (@typeInfo(@TypeOf(expected)).@"struct".fields) |f| {
if (comptime std.mem.eql(u8, f.name, "expires")) {
try testing.expectDelta(expected.expires, cookie.expires, 1);
} else {

View File

@@ -66,7 +66,7 @@ pub fn asUint(comptime string: anytype) AsUintReturn(string) {
fn AsUintReturn(comptime string: anytype) type {
return @Type(.{
.Int = .{
.int = .{
.bits = @bitSizeOf(@TypeOf(string.*)) - 8, // (- 8) to exclude sentinel 0
.signedness = .unsigned,
},

View File

@@ -11,10 +11,10 @@ const App = @import("app.zig").App;
// exactly how to assert equality
pub fn expectEqual(expected: anytype, actual: anytype) !void {
switch (@typeInfo(@TypeOf(actual))) {
.Array => |arr| if (arr.child == u8) {
.array => |arr| if (arr.child == u8) {
return std.testing.expectEqualStrings(expected, &actual);
},
.Pointer => |ptr| {
.pointer => |ptr| {
if (ptr.child == u8) {
return std.testing.expectEqualStrings(expected, actual);
} else if (comptime isStringArray(ptr.child)) {
@@ -23,19 +23,19 @@ pub fn expectEqual(expected: anytype, actual: anytype) !void {
return expectString(expected, actual);
}
},
.Struct => |structType| {
.@"struct" => |structType| {
inline for (structType.fields) |field| {
try expectEqual(@field(expected, field.name), @field(actual, field.name));
}
return;
},
.Optional => {
.optional => {
if (actual == null) {
return std.testing.expectEqual(null, expected);
}
return expectEqual(expected, actual.?);
},
.Union => |union_info| {
.@"union" => |union_info| {
if (union_info.tag_type == null) {
@compileError("Unable to compare untagged union values");
}
@@ -59,12 +59,12 @@ pub fn expectEqual(expected: anytype, actual: anytype) !void {
}
pub fn expectDelta(expected: anytype, actual: anytype, delta: anytype) !void {
if (@typeInfo(@TypeOf(expected)) == .Null) {
if (@typeInfo(@TypeOf(expected)) == .null) {
return std.testing.expectEqual(null, actual);
}
switch (@typeInfo(@TypeOf(actual))) {
.Optional => {
.optional => {
if (actual) |value| {
return expectDelta(expected, value, delta);
}
@@ -74,7 +74,7 @@ pub fn expectDelta(expected: anytype, actual: anytype, delta: anytype) !void {
}
switch (@typeInfo(@TypeOf(expected))) {
.Optional => {
.optional => {
if (expected) |value| {
return expectDelta(value, actual, delta);
}
@@ -96,7 +96,7 @@ pub fn expectDelta(expected: anytype, actual: anytype, delta: anytype) !void {
}
fn isStringArray(comptime T: type) bool {
if (!is(.Array)(T) and !isPtrTo(.Array)(T)) {
if (!is(.array)(T) and !isPtrTo(.array)(T)) {
return false;
}
return std.meta.Elem(T) == u8;
@@ -124,7 +124,7 @@ pub fn isPtrTo(comptime id: std.builtin.TypeId) TraitFn {
pub fn isSingleItemPtr(comptime T: type) bool {
if (comptime is(.pointer)(T)) {
return @typeInfo(T).Pointer.size == .one;
return @typeInfo(T).pointer.size == .one;
}
return false;
}

View File

@@ -420,7 +420,7 @@ fn testParseQuery(expected: anytype, query: []const u8) !void {
defer values.deinit();
var count: usize = 0;
inline for (@typeInfo(@TypeOf(expected)).Struct.fields) |f| {
inline for (@typeInfo(@TypeOf(expected)).@"struct".fields) |f| {
const actual = values.get(f.name);
const expect = @field(expected, f.name);
try testing.expectEqual(expect.len, actual.len);

2
vendor/tls.zig vendored