diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 0bfb420..d717403 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/lightpanda-io/zig-v8:0.12.0-dev.1773-8a8fd47d2 + image: ghcr.io/lightpanda-io/zig-v8:0.12.1 credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/zig-fmt.yml b/.github/workflows/zig-fmt.yml index 39ee8b6..c6cc183 100644 --- a/.github/workflows/zig-fmt.yml +++ b/.github/workflows/zig-fmt.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/lightpanda-io/zig:0.12.0-dev.1773-8a8fd47d2 + image: ghcr.io/lightpanda-io/zig:0.12.1 credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/zig-test.yml b/.github/workflows/zig-test.yml index bb2f434..3f69863 100644 --- a/.github/workflows/zig-test.yml +++ b/.github/workflows/zig-test.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/lightpanda-io/zig-v8:0.12.0-dev.1773-8a8fd47d2 + image: ghcr.io/lightpanda-io/zig-v8:0.12.1 credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -71,7 +71,7 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/lightpanda-io/zig-v8:0.12.0-dev.1773-8a8fd47d2 + image: ghcr.io/lightpanda-io/zig-v8:0.12.1 credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -102,7 +102,7 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/lightpanda-io/zig-v8:0.12.0-dev.1773-8a8fd47d2 + image: ghcr.io/lightpanda-io/zig-v8:0.12.1 credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index a9dc7ce..948b5f7 100644 --- a/README.md +++ b/README.md @@ -146,14 +146,14 @@ $ make shell zig-js-runtime - Javascript Shell exit with Ctrl+D or "exit" -> +> ``` ## Build ### Prerequisites -zig-js-runtime is written with [Zig](https://ziglang.org/) `0.12`. You have to +zig-js-runtime is written with [Zig](https://ziglang.org/) `0.12.1`. You have to install it with the right version in order to build the project. To be able to build the v8 engine, you have to install some libs: diff --git a/build.zig b/build.zig index 3f40dfd..d39db3c 100644 --- a/build.zig +++ b/build.zig @@ -19,7 +19,7 @@ const pkgs = packages(""); /// Do not rename this constant. It is scanned by some scripts to determine /// which zig version to install. -pub const recommended_zig_version = "0.12.0-dev.1773+8a8fd47d2"; +pub const recommended_zig_version = "0.12.1"; pub fn build(b: *std.Build) !void { switch (comptime builtin.zig_version.order(std.SemanticVersion.parse(recommended_zig_version) catch unreachable)) { @@ -48,17 +48,17 @@ pub fn build(b: *std.Build) !void { // compile and install const bench = b.addExecutable(.{ .name = "zig-js-runtime-bench", - .root_source_file = .{ .path = "src/main_bench.zig" }, + .root_source_file = b.path("src/main_bench.zig"), .single_threaded = true, .target = target, .optimize = mode, }); - try common(bench, mode, options); + try common(b, &bench.root_module, options); if (mode == .ReleaseSafe) { // remove debug info // TODO: check if mandatory in release-safe - bench.strip = true; + bench.root_module.strip = true; } b.installArtifact(bench); @@ -78,16 +78,16 @@ pub fn build(b: *std.Build) !void { // compile and install const shell = b.addExecutable(.{ .name = "zig-js-runtime-shell", - .root_source_file = .{ .path = "src/main_shell.zig" }, + .root_source_file = b.path("src/main_shell.zig"), .target = target, .optimize = mode, }); - try common(shell, mode, options); + try common(b, &shell.root_module, options); try pkgs.add_shell(shell); if (mode == .ReleaseSafe) { // remove debug info // TODO: check if mandatory in release-safe - shell.strip = true; + shell.root_module.strip = true; } // do not install shell binary // b.installArtifact(shell); @@ -107,13 +107,13 @@ pub fn build(b: *std.Build) !void { // compile const tests = b.addTest(.{ - .root_source_file = .{ .path = "src/run_tests.zig" }, + .root_source_file = b.path("src/run_tests.zig"), .target = target, .optimize = mode, }); - try common(tests, mode, options); - tests.single_threaded = true; - tests.test_runner = "src/test_runner.zig"; + try common(b, &tests.root_module, options); + tests.root_module.single_threaded = true; + tests.test_runner = b.path("src/test_runner.zig"); const run_tests = b.addRunArtifact(tests); // step @@ -149,15 +149,15 @@ pub fn buildOptions(b: *std.Build) !Options { } fn common( - step: *std.Build.Step.Compile, - mode: std.builtin.Mode, + b: *std.Build, + m: *std.Build.Module, options: Options, ) !void { - step.addOptions("jsruntime_build_options", options.opts); - step.addModule("tigerbeetle-io", pkgs.tigerbeetle_io(step)); + m.addOptions("jsruntime_build_options", options.opts); + m.addImport("tigerbeetle-io", pkgs.tigerbeetle_io(b)); if (options.engine == .v8) { - try pkgs.v8(step, mode); - step.addModule("v8", pkgs.zig_v8(step)); + try pkgs.v8(m); + m.addImport("v8", pkgs.zig_v8(b)); } } @@ -167,33 +167,35 @@ pub fn packages(comptime vendor_path: []const u8) type { const vendor = vendor_path ++ "vendor"; - fn tigerbeetle_io(step: *std.Build.Step.Compile) *std.Build.Module { - return step.step.owner.createModule(.{ - .source_file = .{ .path = vendor ++ "/tigerbeetle-io/io.zig" }, + fn tigerbeetle_io(b: *std.Build) *std.Build.Module { + return b.createModule(.{ + .root_source_file = b.path(vendor ++ "/tigerbeetle-io/io.zig"), }); } - fn zig_v8(step: *std.Build.Step.Compile) *std.Build.Module { - step.addIncludePath(.{ .path = vendor ++ "/zig-v8/src" }); - - return step.step.owner.createModule(.{ - .source_file = .{ .path = vendor ++ "/zig-v8/src/v8.zig" }, + fn zig_v8(b: *std.Build) *std.Build.Module { + const mod = b.createModule(.{ + .root_source_file = b.path(vendor ++ "/zig-v8/src/v8.zig"), + .link_libc = false, + .link_libcpp = false, }); - } - fn v8(step: *std.Build.Step.Compile, mode: std.builtin.Mode) !void { - const mode_str: []const u8 = if (mode == .Debug) "debug" else "release"; - // step.linkLibC(); // TODO: do we need to link libc? + mod.addIncludePath(b.path(vendor ++ "/zig-v8/src")); + + return mod; + } + fn v8(mod: *std.Build.Module) !void { + const mode_str: []const u8 = if (mod.optimize.? == .Debug) "debug" else "release"; // FIXME: we are tied to native v8 builds, currently: // - aarch64-macos // - x86_64-linux - const os = step.target.getOsTag(); - const arch = step.target.getCpuArch(); + const os = mod.resolved_target.?.result.os.tag; + const arch = mod.resolved_target.?.result.cpu.arch; switch (os) { .linux => blk: { // TODO: why do we need it? It should be linked already when we built v8 - step.linkLibCpp(); + mod.link_libcpp = true; break :blk; }, .macos => blk: { @@ -207,45 +209,49 @@ pub fn packages(comptime vendor_path: []const u8) type { } const lib_path = try std.fmt.allocPrint( - step.step.owner.allocator, + mod.owner.allocator, "{s}vendor/v8/{s}-{s}/{s}/libc_v8.a", .{ vendor_path, @tagName(arch), @tagName(os), mode_str }, ); - step.addObjectFile(.{ .path = lib_path }); + mod.addObjectFile(mod.owner.path(lib_path)); } pub fn add_shell(step: *std.Build.Step.Compile) !void { - step.addIncludePath(.{ .path = vendor ++ "/linenoise-mob" }); + step.addIncludePath(step.root_module.owner.path(vendor ++ "/linenoise-mob")); const lib = step.step.owner.addStaticLibrary(.{ .name = "linenoise", - .target = step.target, - .optimize = step.optimize, + .target = step.root_module.resolved_target.?, + .optimize = step.root_module.optimize.?, .link_libc = true, }); // TODO: use mode to add debug/release flags const cflags = &.{}; lib.addCSourceFile(.{ - .file = .{ .path = vendor ++ "/linenoise-mob/linenoise.c" }, + .file = step.root_module.owner.path(vendor ++ "/linenoise-mob/linenoise.c"), .flags = cflags, }); step.linkLibrary(lib); } - pub fn add( - step: *std.build.Step.Compile, + pub fn module( + b: *std.Build, options: Options, - ) !void { - const jsruntime_mod = step.step.owner.createModule(.{ - .source_file = .{ .path = vendor_path ++ "/src/api.zig" }, - .dependencies = &[_]std.build.ModuleDependency{ + mode: std.builtin.Mode, + target: std.Build.ResolvedTarget, + ) !*std.Build.Module { + const mod = b.createModule(.{ + .root_source_file = b.path(vendor_path ++ "/src/api.zig"), + .optimize = mode, + .target = target, + .imports = &[_]std.Build.Module.Import{ .{ .name = "jsruntime_build_options", .module = options.opts.createModule() }, - .{ .name = "tigerbeetle-io", .module = Self.tigerbeetle_io(step) }, - .{ .name = "v8", .module = Self.zig_v8(step) }, + .{ .name = "tigerbeetle-io", .module = Self.tigerbeetle_io(b) }, + .{ .name = "v8", .module = Self.zig_v8(b) }, }, }); - try Self.v8(step, step.optimize); + try Self.v8(mod); - step.addModule("jsruntime", jsruntime_mod); + return mod; } }; } diff --git a/src/engines/v8/generate.zig b/src/engines/v8/generate.zig index 2f889b1..79a371e 100644 --- a/src/engines/v8/generate.zig +++ b/src/engines/v8/generate.zig @@ -168,7 +168,7 @@ fn getNativeArg( // JS object const ptr = try getNativeObject(nat_ctx, T_refl, js_value.castTo(v8.Object)); - if (arg_T.underPtr() != null) { + if (comptime arg_T.underPtr() != null) { value = ptr; } else { value = ptr.*; @@ -389,13 +389,14 @@ fn getArgs( fn freeArgs(alloc: std.mem.Allocator, comptime func: refl.Func, obj: anytype) !void { inline for (func.args) |arg_T| { + const underT = comptime arg_T.underT(); // free char slices // the API functions will be responsible of copying the slice // in their implementations if they want to keep it afterwards - if (arg_T.underT() == []u8 or arg_T.underT() == []const u8) { + if (underT == []u8 or underT == []const u8) { const val = @field(obj, arg_T.name.?); - if (arg_T.underOpt() != null) { + if (comptime arg_T.underOpt() != null) { // free only if val is non-null if (val) |v| { alloc.free(v); @@ -406,7 +407,7 @@ fn freeArgs(alloc: std.mem.Allocator, comptime func: refl.Func, obj: anytype) !v } // free varidadic slices - if (try refl.Type.variadic(arg_T.underT(), null) != null) { + if (try refl.Type.variadic(underT, null) != null) { const val = @field(obj, arg_T.name.?).?; // NOTE: variadic are optional by design alloc.free(@field(val, "slice")); @@ -913,7 +914,7 @@ fn callFunc( // call native func const function = @field(T_refl.T, func.name); - const res_T = func.return_type.underErr() orelse func.return_type.T; + const res_T = comptime func.return_type.underErr() orelse func.return_type.T; var res: res_T = undefined; if (comptime @typeInfo(func.return_type.T) == .ErrorUnion) { res = @call(.auto, function, args) catch |err| { @@ -940,7 +941,7 @@ fn callFunc( nat_ctx.alloc, nat_ctx, T_refl, - func.return_type.underT(), + comptime func.return_type.underT(), res, cbk_info.getThis(), isolate, diff --git a/src/generate.zig b/src/generate.zig index f0b9661..44bc78e 100644 --- a/src/generate.zig +++ b/src/generate.zig @@ -38,15 +38,16 @@ const loadFn = @import("private_api.zig").loadFn; // reflect the user-defined types to obtain type information (T_refl) // This function must be called at comptime by the root file of the project // and stored in a constant named `Types` -pub fn reflect(comptime types: anytype) []refl.Struct { +pub fn reflect(comptime types: anytype) []const refl.Struct { std.debug.assert(@inComptime()); // call types reflection - return refl.do(types) catch unreachable; + const structs: []const refl.Struct = refl.do(types) catch |e| @compileError(@errorName(e)); + return structs; } // Import user-defined types -pub const Types: []refl.Struct = @import("root").Types; +pub const Types: []const refl.Struct = @import("root").Types; // retrieved the reflected type of a user-defined native type pub fn getType(comptime T: type) refl.Struct { @@ -61,7 +62,7 @@ pub fn getType(comptime T: type) refl.Struct { // generate APIs from reflected types // which can be later loaded in JS. -fn generate(comptime types: []refl.Struct) []API { +fn generate(comptime types: []const refl.Struct) []API { std.debug.assert(@inComptime()); var apis: [types.len]API = undefined; @@ -146,7 +147,11 @@ fn MergeTupleT(comptime value: anytype) type { var i = 0; while (i < fields_nb) { fields[i] = .{ - .name = itoa(i), + // StructField.name expect a null terminated string. + // concatenate the `[]const u8` string with an empty string + // literal (`name ++ ""`) to explicitly coerce it to `[:0]const + // u8`. + .name = itoa(i) ++ "", .type = type, .default_value = null, .is_comptime = false, @@ -156,7 +161,7 @@ fn MergeTupleT(comptime value: anytype) type { } const decls: [0]std.builtin.Type.Declaration = undefined; const info = std.builtin.Type.Struct{ - .layout = .Auto, + .layout = .auto, .fields = &fields, .decls = &decls, .is_tuple = true, diff --git a/src/loop.zig b/src/loop.zig index 74f1233..4887d96 100644 --- a/src/loop.zig +++ b/src/loop.zig @@ -75,15 +75,15 @@ pub const SingleThreaded = struct { // Register events atomically // - add 1 event and return previous value fn addEvent(self: *Self) usize { - return @atomicRmw(usize, self.events_nb, .Add, 1, .AcqRel); + return @atomicRmw(usize, self.events_nb, .Add, 1, .acq_rel); } // - remove 1 event and return previous value fn removeEvent(self: *Self) usize { - return @atomicRmw(usize, self.events_nb, .Sub, 1, .AcqRel); + return @atomicRmw(usize, self.events_nb, .Sub, 1, .acq_rel); } // - get the number of current events fn eventsNb(self: *Self) usize { - return @atomicLoad(usize, self.events_nb, .SeqCst); + return @atomicLoad(usize, self.events_nb, .seq_cst); } fn freeCbk(self: *Self, completion: *IO.Completion, ctx: anytype) void { @@ -206,7 +206,7 @@ pub const SingleThreaded = struct { return try self.loop.io.tick(); } - pub fn connect(self: *NetworkImpl, ctx: *Ctx, socket: std.os.socket_t, address: std.net.Address) void { + pub fn connect(self: *NetworkImpl, ctx: *Ctx, socket: std.posix.socket_t, address: std.net.Address) void { self.ctx = ctx; _ = self.loop.addEvent(); self.loop.io.connect(*NetworkImpl, self, NetworkImpl.connectCbk, &self.completion, socket, address); @@ -218,7 +218,7 @@ pub const SingleThreaded = struct { return self.ctx.onConnect(null); } - pub fn receive(self: *NetworkImpl, ctx: *Ctx, socket: std.os.socket_t, buffer: []u8) void { + pub fn receive(self: *NetworkImpl, ctx: *Ctx, socket: std.posix.socket_t, buffer: []u8) void { self.ctx = ctx; _ = self.loop.addEvent(); self.loop.io.recv(*NetworkImpl, self, NetworkImpl.receiveCbk, &self.completion, socket, buffer); @@ -230,7 +230,7 @@ pub const SingleThreaded = struct { return self.ctx.onReceive(ln, null); } - pub fn send(self: *NetworkImpl, ctx: *Ctx, socket: std.os.socket_t, buffer: []const u8) void { + pub fn send(self: *NetworkImpl, ctx: *Ctx, socket: std.posix.socket_t, buffer: []const u8) void { self.ctx = ctx; _ = self.loop.addEvent(); self.loop.io.send(*NetworkImpl, self, NetworkImpl.sendCbk, &self.completion, socket, buffer); diff --git a/src/main_bench.zig b/src/main_bench.zig index ac61674..9c06587 100644 --- a/src/main_bench.zig +++ b/src/main_bench.zig @@ -104,7 +104,7 @@ pub fn main() !void { while (args.next()) |arg| { if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) { try io.getStdErr().writer().print(usage, .{execname}); - std.os.exit(0); + std.posix.exit(0); } else if (std.mem.eql(u8, "--json", arg)) { json = true; } @@ -144,7 +144,7 @@ pub fn main() !void { }; try std.json.stringify(res, .{ .whitespace = .indent_2 }, io.getStdOut().writer()); - std.os.exit(0); + std.posix.exit(0); } // benchmark measures diff --git a/src/pretty.zig b/src/pretty.zig index fb7abb7..03a11a9 100644 --- a/src/pretty.zig +++ b/src/pretty.zig @@ -56,7 +56,11 @@ pub fn GenerateTable( var buf: [1]u8 = undefined; const name = try std.fmt.bufPrint(buf[0..], "{d}", .{i}); fields[i] = std.builtin.Type.StructField{ - .name = name, + // StructField.name expect a null terminated string. + // concatenate the `[]const u8` string with an empty string + // literal (`name ++ ""`) to explicitly coerce it to `[:0]const + // u8`. + .name = name ++ "", .type = T, .default_value = null, .is_comptime = false, @@ -65,7 +69,7 @@ pub fn GenerateTable( } const decls: [0]std.builtin.Type.Declaration = undefined; const shape_info = std.builtin.Type.Struct{ - .layout = std.builtin.Type.ContainerLayout.Auto, + .layout = .auto, .fields = &fields, .decls = &decls, .is_tuple = true, diff --git a/src/reflect.zig b/src/reflect.zig index 211e37a..d8ece2d 100644 --- a/src/reflect.zig +++ b/src/reflect.zig @@ -89,7 +89,7 @@ pub const Type = struct { T_refl_index: ?usize = null, nested_index: ?usize = null, // T_refl_index is mandatory in this case - union_T: ?[]Type, + union_T: ?[]const Type, pub inline fn isNative(comptime self: Type) bool { comptime { @@ -241,7 +241,7 @@ pub const Type = struct { // find if T is a VariadicType // and returns it as a reflect.Type - pub fn variadic(comptime T: type, comptime structs: ?[]Struct) !?Type { + pub fn variadic(comptime T: type, comptime structs: ?[]const Struct) !?Type { std.debug.assert(@inComptime()); const TT = Type._variadic(T) orelse return null; @@ -257,7 +257,7 @@ pub const Type = struct { } // check that user-defined types have been provided as an API - pub fn lookup(comptime self: *Type, comptime structs: []Struct) Error!void { + pub fn lookup(comptime self: *Type, comptime structs: []const Struct) Error!void { std.debug.assert(@inComptime()); // lookup unecessary @@ -274,9 +274,14 @@ pub const Type = struct { // if union, lookup each possible type if (self.union_T) |union_types| { - inline for (union_types) |*tt| { - try tt.lookup(structs); + var uts: [union_types.len]Type = undefined; + inline for (union_types, 0..) |tt, i| { + var t = tt; + try t.lookup(structs); + uts[i] = t; } + const cuts = uts; + self.union_T = &cuts; return; } @@ -316,7 +321,7 @@ pub const Type = struct { } } - fn reflectUnion(comptime T: type, comptime info: std.builtin.Type) Error![]Type { + fn reflectUnion(comptime T: type, comptime info: std.builtin.Type) Error![]const Type { if (info.Union.tag_type == null) { const msg = "union should be a tagged"; fmtErr(msg.len, msg, T); @@ -326,7 +331,9 @@ pub const Type = struct { inline for (info.Union.fields, 0..) |field, i| { union_types[i] = try Type.reflect(field.type, field.name); } - return &union_types; + + const cunion_types = union_types; + return &cunion_types; } pub fn reflect(comptime T: type, comptime name: ?[]const u8) Error!Type { @@ -335,7 +342,7 @@ pub const Type = struct { const info = @typeInfo(Type._underT(T)); // union T - var union_T: ?[]Type = null; + var union_T: ?[]const Type = null; if (info == .Union) { union_T = try reflectUnion(T, info); } @@ -348,17 +355,19 @@ pub const Type = struct { } } + const cunion_T = union_T; + const t = Type{ .T = T, .name = name, - .union_T = union_T, + .union_T = cunion_T, }; return t; } }; const Args = struct { - fn reflect(comptime self_T: ?type, comptime args: []Type) type { + fn reflect(comptime self_T: ?type, comptime args: []const Type) type { var len = args.len; if (self_T != null) { len += 1; @@ -367,7 +376,11 @@ const Args = struct { if (self_T != null) { const name = try itoa(0); fields[0] = std.builtin.Type.StructField{ - .name = name, + // StructField.name expect a null terminated string. + // concatenate the `[]const u8` string with an empty string + // literal (`name ++ ""`) to explicitly coerce it to `[:0]const + // u8`. + .name = name ++ "", .type = self_T.?, .default_value = null, .is_comptime = false, @@ -380,17 +393,22 @@ const Args = struct { x += 1; } fields[x] = std.builtin.Type.StructField{ - .name = arg.name.?, + // StructField.name expect a null terminated string. + // concatenate the `[]const u8` string with an empty string + // literal (`name ++ ""`) to explicitly coerce it to `[:0]const + // u8`. + .name = arg.name.? ++ "", .type = arg.T, .default_value = null, .is_comptime = false, .alignment = @alignOf(arg.T), }; } - const decls: [0]std.builtin.Type.Declaration = undefined; + const decls = [_]std.builtin.Type.Declaration{}; + const cfields = fields; const s = std.builtin.Type.Struct{ - .layout = std.builtin.Type.ContainerLayout.Auto, - .fields = &fields, + .layout = .auto, + .fields = &cfields, .decls = &decls, .is_tuple = true, }; @@ -453,7 +471,7 @@ pub const Func = struct { name: []const u8, // func signature - args: []Type, + args: []const Type, args_T: type, first_optional_arg: ?usize, @@ -470,10 +488,16 @@ pub const Func = struct { setter_index: ?u8, // TODO: not ideal, is there a cleaner solution? - fn lookupTypes(comptime self: *Func, comptime structs: []Struct) Error!void { - inline for (self.args) |*arg| { - try arg.lookup(structs); + fn lookupTypes(comptime self: *Func, comptime structs: []const Struct) Error!void { + // copy args + var args: [self.args.len]Type = undefined; + inline for (self.args, 0..) |arg, i| { + var a = arg; + try a.lookup(structs); + args[i] = a; } + const cargs = args; + self.args = &cargs; try self.return_type.lookup(structs); } @@ -655,8 +679,8 @@ pub const Func = struct { const js_name = jsName(field_name); // reflect args - const args_slice = args_types[0..]; - const args_T = comptime Args.reflect(self_T, args_slice); + const args_slice = args_types; + const args_T = comptime Args.reflect(self_T, &args_slice); // reflect return type const return_type = try Type.reflect(func.Fn.return_type.?, null); @@ -667,7 +691,7 @@ pub const Func = struct { .name = name, // func signature - .args = args_slice, + .args = &args_slice, .args_T = args_T, .first_optional_arg = first_optional_arg, @@ -689,7 +713,7 @@ pub const Func = struct { pub const StructNested = struct { T: type, - fields: []Type, + fields: []const Type, fn isNested(comptime T: type, comptime decl: std.builtin.Type.Declaration) bool { // special keywords @@ -723,7 +747,8 @@ pub const StructNested = struct { inline for (info.Struct.fields, 0..) |field, i| { fields[i] = try Type.reflect(field.type, field.name); } - return .{ .T = T, .fields = &fields }; + const cfields = fields; + return .{ .T = T, .fields = &cfields }; } }; @@ -751,12 +776,12 @@ pub const Struct = struct { has_constructor: bool, constructor: Func, - getters: []Func, - setters: []Func, - methods: []Func, + getters: []const Func, + setters: []const Func, + methods: []const Func, // nested types - nested: []StructNested, + nested: []const StructNested, pub fn Self(comptime self: Struct) type { comptime { @@ -802,20 +827,54 @@ pub const Struct = struct { if (self.has_constructor) { try self.constructor.lookupTypes(structs); } - inline for (self.getters) |*getter| { - try getter.lookupTypes(structs); - } - inline for (self.setters) |*setter| { - try setter.lookupTypes(structs); - } - inline for (self.methods) |*method| { - try method.lookupTypes(structs); - } - inline for (self.nested) |nested| { - inline for (nested.fields) |*field| { - try field.lookup(structs); + + // copy getters + var getters: [self.getters.len]Func = undefined; + inline for (self.getters, 0..) |getter, i| { + var f = getter; + try f.lookupTypes(structs); + getters[i] = f; + } + const cgetters = getters; + self.getters = &cgetters; + + // copy setters + var setters: [self.setters.len]Func = undefined; + inline for (self.setters, 0..) |setter, i| { + var f = setter; + try f.lookupTypes(structs); + setters[i] = f; + } + const csetters = setters; + self.setters = &csetters; + + // copy methods + var methods: [self.methods.len]Func = undefined; + inline for (self.methods, 0..) |method, i| { + var f = method; + try f.lookupTypes(structs); + methods[i] = f; + } + const cmethods = methods; + self.methods = &cmethods; + + // copy nested + var nesteds: [self.nested.len]StructNested = undefined; + inline for (self.nested, 0..) |nested, i| { + var n = nested; + // copy fields + var fields: [nested.fields.len]Type = undefined; + inline for (nested.fields, 0..) |field, j| { + var f = field; + try f.lookup(structs); + fields[j] = f; } + const cfields = fields; + n.fields = &cfields; + nesteds[i] = n; } + const cnesteds = nesteds; + self.nested = &cnesteds; } fn lessThan(_: void, comptime a: Struct, comptime b: Struct) bool { @@ -918,10 +977,11 @@ pub const Struct = struct { }; attrs_done += 1; } + const cfields = fields; return @Type(.{ .Struct = .{ - .layout = .Auto, - .fields = &fields, + .layout = .auto, + .fields = &cfields, .decls = &.{}, .is_tuple = false, }, @@ -1011,7 +1071,7 @@ pub const Struct = struct { // Retrieve the optional Exception of the API, // including from prototype chain - pub fn exception(comptime self: Struct, comptime all: []Struct) ?Struct { + pub fn exception(comptime self: Struct, comptime all: []const Struct) ?Struct { std.debug.assert(@inComptime()); // errors have already been checked at lookup stage @@ -1071,7 +1131,7 @@ pub const Struct = struct { // for layout where fields memory order is guarantied, // check the 'proto' field is the first one - if (@typeInfo(T).Struct.layout != .Auto) { + if (@typeInfo(T).Struct.layout != .auto) { if (i != 0) { const msg = "'proto' field should be the first one if memory layout is guarantied (extern)"; fmtErr(msg.len, msg, T); @@ -1145,7 +1205,7 @@ pub const Struct = struct { // with unknown memory fields, like slices // see: https://github.com/ziglang/zig/issues/2201 // and https://github.com/ziglang/zig/issues/3133 - if (obj.Struct.layout == .Packed) { + if (obj.Struct.layout == .@"packed") { const msg = "type packed struct are not supported"; fmtErr(msg.len, msg, T); return error.StructPacked; @@ -1180,7 +1240,7 @@ pub const Struct = struct { if (@hasDecl(T, "mem_guarantied")) { mem_guarantied = true; } else { - mem_guarantied = @typeInfo(T).Struct.layout != .Auto; + mem_guarantied = @typeInfo(T).Struct.layout != .auto; } // nested types @@ -1336,6 +1396,11 @@ pub const Struct = struct { } } + const cgetters = getters; + const csetters = setters; + const cmethods = methods; + const cnested = nested; + return Struct{ // struct info .name = struct_name, @@ -1356,12 +1421,12 @@ pub const Struct = struct { // struct functions .has_constructor = has_constructor, .constructor = constructor, - .getters = getters[0..], - .setters = setters[0..], - .methods = methods[0..], + .getters = &cgetters, + .setters = &csetters, + .methods = &cmethods, // nested types - .nested = nested[0..], + .nested = &cnested, }; } }; @@ -1445,7 +1510,7 @@ fn lookupException(comptime all: []Struct) Error!void { } } -pub fn do(comptime types: anytype) Error![]Struct { +pub fn do(comptime types: anytype) Error![]const Struct { comptime { // check types provided @@ -1488,7 +1553,9 @@ pub fn do(comptime types: anytype) Error![]Struct { try s.lookupTypes(&all); } - return &all; + // handle comptime var. + const call = all; + return &call; } } @@ -1610,20 +1677,25 @@ fn assertFuncReturnT(comptime func: type, comptime T: type, comptime opts: EqlOp // createTupleT generate a tuple type // with the members passed as fields -fn createTupleT(comptime members: []type) type { +fn createTupleT(comptime members: []const type) type { var fields: [members.len]std.builtin.Type.StructField = undefined; for (members, 0..) |member, i| { fields[i] = std.builtin.Type.StructField{ - .name = try itoa(i), + // StructField.name expect a null terminated string. + // concatenate the `[]const u8` string with an empty string + // literal (`name ++ ""`) to explicitly coerce it to `[:0]const + // u8`. + .name = try itoa(i) ++ "", .type = member, .default_value = null, .is_comptime = false, .alignment = @alignOf(member), }; } + const cfields = fields; const s = std.builtin.Type.Struct{ - .layout = std.builtin.Type.ContainerLayout.Auto, - .fields = &fields, + .layout = .auto, + .fields = &cfields, .decls = &.{}, .is_tuple = true, }; @@ -1640,7 +1712,8 @@ fn argsT(comptime func: type) type { for (info.params, 0..) |param, i| { params[i] = param.type.?; } - return createTupleT(¶ms); + const cparams = params; + return createTupleT(&cparams); } // public functions @@ -1729,7 +1802,8 @@ fn jsName(comptime name: []const u8) []const u8 { } js_name[i] = char; } - return &js_name; + const cname = js_name; + return &cname; } fn shortName(comptime T: type) []const u8 { @@ -1737,9 +1811,11 @@ fn shortName(comptime T: type) []const u8 { return it.first(); } -pub fn itoa(i: u8) ![]u8 { +pub fn itoa(i: u8) ![]const u8 { var buf: [1]u8 = undefined; - return try std.fmt.bufPrint(buf[0..], "{d}", .{i}); + _ = try std.fmt.bufPrint(buf[0..], "{d}", .{i}); + const cbuf = buf; + return &cbuf; } fn isStringLiteral(comptime T: type) bool { diff --git a/src/refs.zig b/src/refs.zig index 88987c0..b4a1cb2 100644 --- a/src/refs.zig +++ b/src/refs.zig @@ -25,7 +25,7 @@ const refl = internal.refl; // - value is the index of API pub const Map = std.AutoHashMapUnmanaged(usize, usize); -pub fn getObject(map: Map, comptime T: type, comptime types: []refl.Struct, ptr: anytype) !*T { +pub fn getObject(map: Map, comptime T: type, comptime types: []const refl.Struct, ptr: anytype) !*T { // use the object pointer (key) to retrieve the API index (value) in the map const ptr_aligned: *align(@alignOf(usize)) anyopaque = @alignCast(ptr); diff --git a/src/run_tests.zig b/src/run_tests.zig index a461f70..d9ca2c8 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -48,7 +48,7 @@ const do_userctx = true; // tests nb const tests_nb = blk: { - comptime var nb = 0; + var nb = 0; if (do_proto) nb += 1; if (do_prim) nb += 1; if (do_nat) nb += 1; diff --git a/src/shell.zig b/src/shell.zig index 34ce5dd..a38bca8 100644 --- a/src/shell.zig +++ b/src/shell.zig @@ -24,7 +24,7 @@ const public = @import("api.zig"); const IO = @import("loop.zig").IO; // Global variables -var socket_fd: std.os.socket_t = undefined; +var socket_fd: std.posix.socket_t = undefined; var conf: Config = undefined; // Config @@ -56,7 +56,7 @@ pub const Config = struct { self.history_max = history_max_default; } if (self.history_path == null) { - const home = std.os.getenv("HOME").?; + const home = std.posix.getenv("HOME").?; // NOTE: we are using bufPrintZ as we need a null-terminated slice // to translate as c char self.history_path = try std.fmt.bufPrintZ( @@ -73,7 +73,7 @@ pub const Config = struct { // I/O connection context const ConnContext = struct { - socket: std.os.socket_t, + socket: std.posix.socket_t, cmdContext: *CmdContext, }; @@ -82,7 +82,7 @@ const ConnContext = struct { fn connCallback( ctx: *ConnContext, completion: *IO.Completion, - result: IO.AcceptError!std.os.socket_t, + result: IO.AcceptError!std.posix.socket_t, ) void { ctx.cmdContext.socket = result catch |err| @panic(@errorName(err)); @@ -101,7 +101,7 @@ fn connCallback( const CmdContext = struct { alloc: std.mem.Allocator, js_env: *public.Env, - socket: std.os.socket_t, + socket: std.posix.socket_t, buf: []u8, close: bool = false, @@ -153,7 +153,7 @@ fn cmdCallback( } // acknowledge to repl result has been printed - _ = std.os.write(ctx.socket, "ok") catch unreachable; + _ = std.posix.write(ctx.socket, "ok") catch unreachable; // continue receving messages asynchronously ctx.js_env.nat_ctx.loop.io.recv( @@ -255,7 +255,7 @@ pub fn shell( // reuse_address (SO_REUSEADDR flag) does not seems to work on unix socket // see: https://gavv.net/articles/unix-socket-reuse/ // TODO: use a lock file instead - std.os.unlink(conf.socket_path.?) catch |err| { + std.posix.unlink(conf.socket_path.?) catch |err| { if (err != error.FileNotFound) { return err; } @@ -263,10 +263,10 @@ pub fn shell( // create internal server listening on a unix socket const addr = try std.net.Address.initUnix(conf.socket_path.?); - var server = std.net.StreamServer.init(.{ .reuse_address = true }); + var server = try addr.listen(.{ .reuse_address = true, .reuse_port = true }); defer server.deinit(); - try server.listen(addr); - socket_fd = server.sockfd.?; + + socket_fd = server.stream.handle; // launch repl in a separate detached thread var repl_thread = try std.Thread.spawn(.{}, repl, .{}); diff --git a/src/tests/test_utils.zig b/src/tests/test_utils.zig index 557c6ed..3904769 100644 --- a/src/tests/test_utils.zig +++ b/src/tests/test_utils.zig @@ -35,7 +35,7 @@ fn isTypeError(expected: []const u8, msg: []const u8) bool { pub fn sleep(nanoseconds: u64) void { const s = nanoseconds / std.time.ns_per_s; const ns = nanoseconds % std.time.ns_per_s; - std.os.nanosleep(s, ns); + std.posix.nanosleep(s, ns); } // result memory is owned by the caller diff --git a/vendor/tigerbeetle-io b/vendor/tigerbeetle-io index 885fc61..aacd974 160000 --- a/vendor/tigerbeetle-io +++ b/vendor/tigerbeetle-io @@ -1 +1 @@ -Subproject commit 885fc61c79a92ecd2c576a0c86306784412593c8 +Subproject commit aacd974394cc1ffa94f779484ca5ba58c9871441 diff --git a/vendor/zig-v8 b/vendor/zig-v8 index bf5d995..958ec32 160000 --- a/vendor/zig-v8 +++ b/vendor/zig-v8 @@ -1 +1 @@ -Subproject commit bf5d995614ce8588ddd74828a780e7829df68b8e +Subproject commit 958ec32d3e4e3ba132bb333d908b9b0d038ab7ae