From c26d563898b44ff82f04a5f994f2edf34ecb5929 Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Mon, 7 Apr 2025 21:16:06 +0100 Subject: [PATCH] Zig 0.15 compatibility Various dependencies updated after changes to `std.zig.Ast` and `std.LinkedList` and other things. --- .github/workflows/CI.yml | 4 +- build.zig | 6 ++- build.zig.zon | 32 ++++++------ cli/build.zig.zon | 4 +- demo/Makefile | 44 +++++++++++++++++ demo/compose.yml | 7 +++ demo/config/database.zig | 9 ++++ demo/src/app/database/Schema.zig | 19 +++++--- src/Routes.zig | 46 ++++++++--------- src/commands/database.zig | 84 +++++++++++++++++++++----------- src/jetzig/loggers/LogQueue.zig | 27 +++++----- 11 files changed, 188 insertions(+), 94 deletions(-) create mode 100644 demo/Makefile create mode 100644 demo/compose.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 994845b..4d1ced0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -30,7 +30,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v1 with: - version: latest + version: master - run: zig version - run: zig env @@ -51,7 +51,7 @@ jobs: JETQUERY_HOSTNAME: 'localhost' JETQUERY_USERNAME: 'postgres' JETQUERY_PASSWORD: 'postgres' - JETQUERY_DATABASE: 'test' + JETQUERY_DATABASE: 'jetzig_demo_test' # Assume a small amount of connections are allowed # into postgres JETQUERY_POOL_SIZE: 2 diff --git a/build.zig b/build.zig index f54d3fe..b536882 100644 --- a/build.zig +++ b/build.zig @@ -425,6 +425,8 @@ fn registerDatabaseSteps(b: *std.Build, exe_database: *std.Build.Step.Compile) v .{ "create", "Create a database for your Jetzig app." }, .{ "drop", "Drop your Jetzig app's database." }, .{ "reflect", "Read your app's database and generate a JetQuery schema." }, + .{ "setup", "Create the database, run migrations, and generate schema." }, + .{ "update", "Run migrations and generate schema." }, }; inline for (commands) |command| { @@ -466,10 +468,10 @@ fn getMarkdownFragmentsSource(allocator: std.mem.Allocator, source: [:0]const u8 for (ast.nodes.items(.tag), 0..) |tag, index| { switch (tag) { .simple_var_decl => { - const decl = ast.simpleVarDecl(@intCast(index)); + const decl = ast.simpleVarDecl(@enumFromInt(index)); const identifier = ast.tokenSlice(decl.ast.mut_token + 1); if (std.mem.eql(u8, identifier, "markdown_fragments")) { - return ast.getNodeSource(@intCast(index)); + return ast.getNodeSource(@enumFromInt(index)); } }, else => continue, diff --git a/build.zig.zon b/build.zig.zon index c438286..3747d44 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -3,30 +3,14 @@ .version = "0.0.0", .fingerprint = 0x93ad8bfa2d209022, .dependencies = .{ - .jetquery = .{ - .url = "https://github.com/jetzig-framework/jetquery/archive/6c3fa3c8557d24b8e6a022632909d162e86be5d7.tar.gz", - .hash = "jetquery-0.0.0-TNf3zjZWBgCLlUMITutBU9dP72AfSVYobcdYJ4AmJT2H", - }, - .jetkv = .{ - .url = "https://github.com/jetzig-framework/jetkv/archive/9d754e552e7569239a900ed9e0f313a0554ed2d3.tar.gz", - .hash = "122013f8596bc615990fd7771c833cab4d2959ecac8d05c4f6c973aa46624e43afea", - }, .jetcommon = .{ .url = "https://github.com/jetzig-framework/jetcommon/archive/fb4edc13759d87bfcd9b1f5fcefdf93f8c9c62dd.tar.gz", .hash = "jetcommon-0.1.0-jPY_DS1HAAAP8xp5HSWB_ZY7m9JEYUmm8adQFrse0lwB", }, - .zmpl = .{ - .url = "https://github.com/jetzig-framework/zmpl/archive/3ec11289fdee2e0c70975cb5dd85d3041d723912.tar.gz", - .hash = "zmpl-0.0.1-SYFGBuZoAwAMuvHNkO_1BbutpWhg7CdSgYd8t4OaaZeR", - }, .zmd = .{ .url = "https://github.com/jetzig-framework/zmd/archive/d6c8aa9a9cde99674ccb096d8f94ed09cba8dab.tar.gz", .hash = "1220d0e8734628fd910a73146e804d10a3269e3e7d065de6bb0e3e88d5ba234eb163", }, - .httpz = .{ - .url = "https://github.com/karlseguin/http.zig/archive/eced2d8c37f921a2dfc8ab639964cdc9b505a888.tar.gz", - .hash = "httpz-0.0.0-AAAAAL6qBgAeyws7FZLTv3e_Sbsjg4PKfB1Fg6AOHctf", - }, .smtp_client = .{ .url = "https://github.com/karlseguin/smtp_client.zig/archive/5163c66cc42cdd93176a6b1cad45f3db3a291a6a.tar.gz", .hash = "smtp_client-0.0.1-AAAAAIJkAQCngHtRYVUMsMuncmicSHK_7ugwWibDzQ4S", @@ -35,6 +19,22 @@ .url = "https://github.com/bobf/zig-args/archive/88cbade9a517a4014824f8f53f3c48c8a0b2ffe1.tar.gz", .hash = "zig_args-0.0.0-jqtN6P_NAAC97fGpk9hS2K681jkiqPsWP6w3ucb_ctGH", }, + .jetkv = .{ + .url = "https://github.com/jetzig-framework/jetkv/archive/5a94e3bac0a6e291efc9d6534beb2d311671ff17.tar.gz", + .hash = "jetkv-0.0.0-zCv0fmCGAgCyYqwHjk0P5KrYVRew1MJAtbtAcIO-WPpT", + }, + .zmpl = .{ + .url = "https://github.com/jetzig-framework/zmpl/archive/c57fc9b83027e8c1459d9625c3509f59f0fb89f3.tar.gz", + .hash = "zmpl-0.0.1-SYFGBgdqAwDeA6xm4KAhpKoNrWs5CMQK6x447zhWclCs", + }, + .httpz = .{ + .url = "https://github.com/karlseguin/http.zig/archive/37d7cb9819b804ade5f4b974b82f8dd0622225ed.tar.gz", + .hash = "httpz-0.0.0-PNVzrEK4BgBpHQGA2m0RPqPGEjnTdDXHodBwzjYDrmps", + }, + .jetquery = .{ + .url = "https://github.com/jetzig-framework/jetquery/archive/e1f969f2e3e0e1ad9cc30d56fde9739aa692fdc3.tar.gz", + .hash = "jetquery-0.0.0-TNf3zo2ABgBgcsIAvJ1Ud2B2zDzrBy9GQ31kKmTYZ7Ya", + }, }, .paths = .{ diff --git a/cli/build.zig.zon b/cli/build.zig.zon index 56c129c..bb04aa6 100644 --- a/cli/build.zig.zon +++ b/cli/build.zig.zon @@ -10,8 +10,8 @@ .hash = "zig_args-0.0.0-jqtN6P_NAAC97fGpk9hS2K681jkiqPsWP6w3ucb_ctGH", }, .jetquery = .{ - .url = "https://github.com/jetzig-framework/jetquery/archive/6c3fa3c8557d24b8e6a022632909d162e86be5d7.tar.gz", - .hash = "jetquery-0.0.0-TNf3zjZWBgCLlUMITutBU9dP72AfSVYobcdYJ4AmJT2H", + .url = "https://github.com/jetzig-framework/jetquery/archive/e1f969f2e3e0e1ad9cc30d56fde9739aa692fdc3.tar.gz", + .hash = "jetquery-0.0.0-TNf3zo2ABgBgcsIAvJ1Ud2B2zDzrBy9GQ31kKmTYZ7Ya", }, }, .paths = .{ diff --git a/demo/Makefile b/demo/Makefile new file mode 100644 index 0000000..feb12b5 --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,44 @@ +# Makefile +# +# Use this Makefile to set up a local Docker PostgreSQL database and run tests, or launch a local +# development database. +# +## Tests +# +# Set up test database and run application tests: +# +# ``` +# make test +# ``` +# +## Development +# +# Set up development database and launch the demo Jetzig app: +# +# ``` +# make dev +# ``` +# +# TODO: Move all of this into `build.zig` +test_database=jetzig_demo_test +dev_database=jetzig_demo_dev +port=14173 + +export JETQUERY_HOSTNAME=localhost +export JETQUERY_USERNAME=postgres +export JETQUERY_PASSWORD=postgres +export JETQUERY_POOL_SIZE=2 + +.PHONY: test +test: env=JETQUERY_DATABASE=${test_database} JETQUERY_PORT=${port} +test: + docker compose up --detach --wait --renew-anon-volumes --remove-orphans --force-recreate + ${env} zig build -Denvironment=testing jetzig:database:setup + ${env} zig build -Denvironment=testing jetzig:test + +.PHONY: dev +dev: env=JETQUERY_DATABASE=${dev_database} JETQUERY_PORT=${port} +dev: + docker compose up --detach --wait --renew-anon-volumes --remove-orphans + ${env} zig build -Denvironment=testing jetzig:database:setup + ${env} jetzig server diff --git a/demo/compose.yml b/demo/compose.yml new file mode 100644 index 0000000..d2c3bd8 --- /dev/null +++ b/demo/compose.yml @@ -0,0 +1,7 @@ +services: + postgres: + image: postgres:17 + ports: + - 14173:5432 + environment: + POSTGRES_PASSWORD: 'postgres' diff --git a/demo/config/database.zig b/demo/config/database.zig index 2c1e6d3..79d7960 100644 --- a/demo/config/database.zig +++ b/demo/config/database.zig @@ -1,7 +1,16 @@ pub const database = .{ + .development = .{ + .adapter = .postgresql, + .username = "postgres", + .password = "postgres", + .hostname = "localhost", + .database = "jetzig_demo_dev", + .port = 14173, // See `compose.yml` + }, // This configuration is used for CI // in GitHub .testing = .{ .adapter = .postgresql, + .database = "jetzig_demo_test", }, }; diff --git a/demo/src/app/database/Schema.zig b/demo/src/app/database/Schema.zig index 436770d..ff8dec7 100644 --- a/demo/src/app/database/Schema.zig +++ b/demo/src/app/database/Schema.zig @@ -1,9 +1,14 @@ const jetquery = @import("jetzig").jetquery; -pub const User = jetquery.Model(@This(), "users", struct { - id: i32, - email: []const u8, - password_hash: []const u8, - created_at: jetquery.DateTime, - updated_at: jetquery.DateTime, -}, .{}); +pub const User = jetquery.Model( + @This(), + "users", + struct { + id: i32, + email: []const u8, + password_hash: []const u8, + created_at: jetquery.DateTime, + updated_at: jetquery.DateTime, + }, + .{}, +); diff --git a/src/Routes.zig b/src/Routes.zig index 8f8707d..ba88730 100644 --- a/src/Routes.zig +++ b/src/Routes.zig @@ -390,7 +390,7 @@ fn generateRoutesForView(self: *Routes, dir: std.fs.Dir, path: []const u8) !Rout for (self.ast.nodes.items(.tag), 0..) |tag, index| { switch (tag) { .fn_proto_multi, .fn_proto_one, .fn_proto_simple => |function_tag| { - var function = try self.parseFunction(function_tag, index, path, source); + var function = try self.parseFunction(function_tag, @enumFromInt(index), path, source); if (function) |*capture| { if (capture.args.len == 0) { std.debug.print( @@ -414,7 +414,7 @@ fn generateRoutesForView(self: *Routes, dir: std.fs.Dir, path: []const u8) !Rout } }, .simple_var_decl => { - const decl = self.ast.simpleVarDecl(asNodeIndex(index)); + const decl = self.ast.simpleVarDecl(@enumFromInt(index)); if (self.isStaticParamsDecl(decl)) { self.data.reset(); const params = try self.data.root(.object); @@ -452,10 +452,11 @@ fn generateRoutesForView(self: *Routes, dir: std.fs.Dir, path: []const u8) !Rout // Parse the `pub const static_params` definition and into a `jetzig.data.Value`. fn parseStaticParamsDecl(self: *Routes, decl: std.zig.Ast.full.VarDecl, params: *jetzig.data.Value) !void { - const init_node = self.ast.nodes.items(.tag)[decl.ast.init_node]; - switch (init_node) { + const init_node = decl.ast.init_node.unwrap() orelse return; + + switch (self.ast.nodeTag(init_node)) { .struct_init_dot_two, .struct_init_dot_two_comma => { - try self.parseStruct(decl.ast.init_node, params); + try self.parseStruct(init_node, params); }, else => return, } @@ -488,14 +489,14 @@ fn parseArray(self: *Routes, node: std.zig.Ast.Node.Index, params: *jetzig.data. const array = maybe_array.?; - const main_token = self.ast.nodes.items(.main_token)[node]; + const main_token = self.ast.nodeMainToken(node); const field_name = self.ast.tokenSlice(main_token - 3); const params_array = try self.data.array(); try params.put(field_name, params_array); for (array.ast.elements) |element| { - const elem = self.ast.nodes.items(.tag)[element]; + const elem = self.ast.nodeTag(element); switch (elem) { .struct_init_dot, .struct_init_dot_two, .struct_init_dot_two_comma => { const route_params = try self.data.object(); @@ -508,20 +509,20 @@ fn parseArray(self: *Routes, node: std.zig.Ast.Node.Index, params: *jetzig.data. try self.parseField(element, route_params); }, .string_literal => { - const string_token = self.ast.nodes.items(.main_token)[element]; + const string_token = self.ast.nodeMainToken(element); const string_value = self.ast.tokenSlice(string_token); // Strip quotes: `"foo"` -> `foo` try params_array.append(string_value[1 .. string_value.len - 1]); }, .number_literal => { - const number_token = self.ast.nodes.items(.main_token)[element]; + const number_token = self.ast.nodeMainToken(element); const number_value = self.ast.tokenSlice(number_token); try params_array.append(try parseNumber(number_value, self.data)); }, inline else => { @setEvalBranchQuota(10_000); - const tag = self.ast.nodes.items(.tag)[element]; + const tag = self.ast.nodeTag(element); std.debug.print("Unexpected token: {}\n", .{tag}); return error.JetzigStaticParamsParseError; }, @@ -531,22 +532,21 @@ fn parseArray(self: *Routes, node: std.zig.Ast.Node.Index, params: *jetzig.data. // Parse the value of a param field (recursively when field is a struct/array) fn parseField(self: *Routes, node: std.zig.Ast.Node.Index, params: *jetzig.data.Value) anyerror!void { - const tag = self.ast.nodes.items(.tag)[node]; - switch (tag) { + switch (self.ast.nodeTag(node)) { // Route params, e.g. `.index = .{ ... }` .array_init_dot, .array_init_dot_two, .array_init_dot_comma, .array_init_dot_two_comma => { try self.parseArray(node, params); }, .struct_init_dot, .struct_init_dot_two, .struct_init_dot_two_comma => { const nested_params = try self.data.object(); - const main_token = self.ast.nodes.items(.main_token)[node]; + const main_token = self.ast.nodeMainToken(node); const field_name = self.ast.tokenSlice(main_token - 3); try params.put(field_name, nested_params); try self.parseStruct(node, nested_params); }, // Individual param in a params struct, e.g. `.foo = "bar"` .string_literal => { - const main_token = self.ast.nodes.items(.main_token)[node]; + const main_token = self.ast.nodeMainToken(node); const field_name = self.ast.tokenSlice(main_token - 2); const field_value = self.ast.tokenSlice(main_token); @@ -557,13 +557,13 @@ fn parseField(self: *Routes, node: std.zig.Ast.Node.Index, params: *jetzig.data. ); }, .number_literal => { - const main_token = self.ast.nodes.items(.main_token)[node]; + const main_token = self.ast.nodeMainToken(node); const field_name = self.ast.tokenSlice(main_token - 2); const field_value = self.ast.tokenSlice(main_token); try params.put(field_name, try parseNumber(field_value, self.data)); }, - else => { + else => |tag| { std.debug.print("Unexpected token: {}\n", .{tag}); return error.JetzigStaticParamsParseError; }, @@ -594,16 +594,16 @@ fn isStaticParamsDecl(self: *Routes, decl: std.zig.Ast.full.VarDecl) bool { fn parseFunction( self: *Routes, function_type: std.zig.Ast.Node.Tag, - index: usize, + index: std.zig.Ast.Node.Index, path: []const u8, source: []const u8, ) !?Function { var buf: [1]std.zig.Ast.Node.Index = undefined; const fn_proto = switch (function_type) { - .fn_proto_multi => self.ast.fnProtoMulti(@as(u32, @intCast(index))), - .fn_proto_one => self.ast.fnProtoOne(&buf, @as(u32, @intCast(index))), - .fn_proto_simple => self.ast.fnProtoSimple(&buf, @as(u32, @intCast(index))), + .fn_proto_multi => self.ast.fnProtoMulti(index), + .fn_proto_one => self.ast.fnProtoOne(&buf, index), + .fn_proto_simple => self.ast.fnProtoSimple(&buf, index), else => unreachable, }; if (fn_proto.name_token) |token| { @@ -620,7 +620,7 @@ fn parseFunction( while (it.next()) |arg| { if (arg.name_token) |arg_token| { const arg_name = self.ast.tokenSlice(arg_token); - const node = self.ast.nodes.get(arg.type_expr); + const node = self.ast.nodes.get(@intFromEnum(arg.type_expr.?)); const type_name = try self.parseTypeExpr(node); try args.append(.{ .name = arg_name, .type_name = type_name }); } @@ -666,10 +666,6 @@ fn parseTypeExpr(self: *Routes, node: std.zig.Ast.Node) ![]const u8 { return error.JetzigAstParserError; } -fn asNodeIndex(index: usize) std.zig.Ast.Node.Index { - return @as(std.zig.Ast.Node.Index, @intCast(index)); -} - fn isActionFunctionName(name: []const u8) bool { inline for (@typeInfo(jetzig.views.Route.Action).@"enum".fields) |field| { if (std.mem.eql(u8, field.name, name)) return true; diff --git a/src/commands/database.zig b/src/commands/database.zig index 9594455..39bc422 100644 --- a/src/commands/database.zig +++ b/src/commands/database.zig @@ -15,7 +15,7 @@ const production_drop_failure_message = "To drop a production database, " ++ const environment = jetzig.build_options.environment; const config = @field(jetquery.config.database, @tagName(environment)); -const Action = enum { migrate, rollback, create, drop, reflect }; +const Action = enum { migrate, rollback, create, drop, reflect, setup, update }; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -46,6 +46,8 @@ pub fn main() !void { .{ "create", .create }, .{ "drop", .drop }, .{ "reflect", .reflect }, + .{ "setup", .setup }, + .{ "update", .update }, }); const action = map.get(args[1]) orelse return error.JetzigUnrecognizedArgument; @@ -77,6 +79,25 @@ pub fn main() !void { defer repo.deinit(); try repo.createDatabase(database, .{}); }, + .setup => { + { + var repo = try migrationsRepo(.create, allocator, repo_env); + defer repo.deinit(); + try repo.createDatabase(database, .{}); + } + { + var repo = try migrationsRepo(.update, allocator, repo_env); + defer repo.deinit(); + try Migrate(config.adapter).init(&repo).migrate(); + try reflectSchema(allocator, repo_env); + } + }, + .update => { + var repo = try migrationsRepo(action, allocator, repo_env); + defer repo.deinit(); + try Migrate(config.adapter).init(&repo).migrate(); + try reflectSchema(allocator, repo_env); + }, .drop => { if (environment == .production) { const confirm = std.process.getEnvVarOwned(allocator, confirm_drop_env) catch |err| { @@ -103,33 +124,7 @@ pub fn main() !void { } }, .reflect => { - var cwd = try jetzig.util.detectJetzigProjectDir(); - defer cwd.close(); - - const Repo = jetquery.Repo(config.adapter, Schema); - var repo = try Repo.loadConfig( - allocator, - std.enums.nameCast(jetquery.Environment, environment), - .{ .context = .migration, .env = repo_env }, - ); - const reflect = @import("jetquery_reflect").Reflect(config.adapter, Schema).init( - allocator, - &repo, - .{ - .import_jetquery = - \\@import("jetzig").jetquery - , - }, - ); - const schema = try reflect.generateSchema(); - const project_dir = try jetzig.util.detectJetzigProjectDir(); - const project_dir_realpath = try project_dir.realpathAlloc(allocator, "."); - const path = try std.fs.path.join( - allocator, - &.{ project_dir_realpath, "src", "app", "database", "Schema.zig" }, - ); - try jetzig.util.createFile(path, schema); - std.log.info("Database schema written to `{s}`.", .{path}); + try reflectSchema(allocator, repo_env); }, } } @@ -141,12 +136,43 @@ fn migrationsRepo(action: Action, allocator: std.mem.Allocator, repo_env: anytyp std.enums.nameCast(jetquery.Environment, environment), .{ .admin = switch (action) { - .migrate, .rollback => false, + .migrate, .rollback, .update => false, .create, .drop => true, .reflect => unreachable, // We use a separate repo for schema reflection. + .setup => unreachable, // Setup uses `create` and then `update` }, .context = .migration, .env = repo_env, }, ); } + +fn reflectSchema(allocator: std.mem.Allocator, repo_env: anytype) !void { + var cwd = try jetzig.util.detectJetzigProjectDir(); + defer cwd.close(); + + const Repo = jetquery.Repo(config.adapter, Schema); + var repo = try Repo.loadConfig( + allocator, + std.enums.nameCast(jetquery.Environment, environment), + .{ .context = .migration, .env = repo_env }, + ); + const reflect = @import("jetquery_reflect").Reflect(config.adapter, Schema).init( + allocator, + &repo, + .{ + .import_jetquery = + \\@import("jetzig").jetquery + , + }, + ); + const schema = try reflect.generateSchema(); + const project_dir = try jetzig.util.detectJetzigProjectDir(); + const project_dir_realpath = try project_dir.realpathAlloc(allocator, "."); + const path = try std.fs.path.join( + allocator, + &.{ project_dir_realpath, "src", "app", "database", "Schema.zig" }, + ); + try jetzig.util.createFile(path, schema); + std.log.info("Database schema written to `{s}`.", .{path}); +} diff --git a/src/jetzig/loggers/LogQueue.zig b/src/jetzig/loggers/LogQueue.zig index f17c028..abd722c 100644 --- a/src/jetzig/loggers/LogQueue.zig +++ b/src/jetzig/loggers/LogQueue.zig @@ -6,11 +6,15 @@ const jetzig = @import("../../jetzig.zig"); const buffer_size = jetzig.config.get(usize, "log_message_buffer_len"); const max_pool_len = jetzig.config.get(usize, "max_log_pool_len"); -const List = std.DoublyLinkedList(Event); +const List = std.DoublyLinkedList; +const ListNode = struct { + event: Event, + node: std.DoublyLinkedList.Node = .{}, +}; const Buffer = [buffer_size]u8; allocator: std.mem.Allocator, -node_allocator: std.heap.MemoryPool(List.Node), +node_allocator: std.heap.MemoryPool(ListNode), buffer_allocator: std.heap.MemoryPool(Buffer), list: List, read_write_mutex: std.Thread.Mutex, @@ -18,7 +22,7 @@ condition: std.Thread.Condition, condition_mutex: std.Thread.Mutex, writer: Writer = undefined, reader: Reader = undefined, -node_pool: std.ArrayList(*List.Node), +node_pool: std.ArrayList(*ListNode), buffer_pool: std.ArrayList(*Buffer), position: usize, stdout_is_tty: bool = undefined, @@ -42,13 +46,13 @@ const Event = struct { pub fn init(allocator: std.mem.Allocator) LogQueue { return .{ .allocator = allocator, - .node_allocator = initPool(allocator, List.Node), + .node_allocator = initPool(allocator, ListNode), .buffer_allocator = initPool(allocator, Buffer), .list = List{}, .condition = std.Thread.Condition{}, .condition_mutex = std.Thread.Mutex{}, .read_write_mutex = std.Thread.Mutex{}, - .node_pool = std.ArrayList(*List.Node).init(allocator), + .node_pool = std.ArrayList(*ListNode).init(allocator), .buffer_pool = std.ArrayList(*Buffer).init(allocator), .position = 0, }; @@ -237,8 +241,8 @@ fn append(self: *LogQueue, event: Event) !void { self.position += 1; - node.* = .{ .data = event }; - self.list.append(node); + node.* = .{ .event = event }; + self.list.append(&node.node); self.condition.signal(); } @@ -249,16 +253,17 @@ fn popFirst(self: *LogQueue) !?Event { defer self.read_write_mutex.unlock(); if (self.list.popFirst()) |node| { - const value = node.data; + const list_node: *ListNode = @fieldParentPtr("node", node); + const value = list_node.event; self.position -= 1; if (self.position < self.node_pool.items.len) { - self.node_pool.items[self.position] = node; + self.node_pool.items[self.position] = list_node; } else { if (self.node_pool.items.len >= max_pool_len) { - self.node_allocator.destroy(node); + self.node_allocator.destroy(list_node); self.position += 1; } else { - try self.node_pool.append(node); + try self.node_pool.append(list_node); } } return value;