diff --git a/build.zig b/build.zig index d704b1d..6fb9c0f 100644 --- a/build.zig +++ b/build.zig @@ -1,5 +1,7 @@ const std = @import("std"); +const Translator = @import("translate_c").Translator; + pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); @@ -57,16 +59,18 @@ pub fn build(b: *std.Build) void { flags.append(b.allocator, "-DSQLITE_USE_URI") catch @panic("OOM"); const sqlite_amalgamation = b.dependency("sqlite_amalgamation", .{}); + const translate_c_dep = b.dependency("translate_c", .{}); - // Translate sqlite3.h to a Zig module via the build system (replaces @cImport) - const translate_c = b.addTranslateC(.{ - .root_source_file = sqlite_amalgamation.path("sqlite3.h"), + // Translate sqlite3.h to a Zig module via translate-c dep (replaces build system impl). + const t: Translator = .init(translate_c_dep, .{ + .c_source_file = sqlite_amalgamation.path("sqlite3.h"), .target = target, .optimize = optimize, .link_libc = true, }); - translate_c.addIncludePath(sqlite_amalgamation.path(".")); - const c_module = translate_c.createModule(); + t.addIncludePath(sqlite_amalgamation.path(".")); + + const c_module = t.mod; const sqlite = b.addModule("sqlite", .{ .root_source_file = b.path("src/sqlite.zig"), @@ -74,7 +78,10 @@ pub fn build(b: *std.Build) void { .{ .name = "c", .module = c_module }, }, }); - sqlite.addCSourceFile(.{ .file = sqlite_amalgamation.path("sqlite3.c"), .flags = flags.items }); + sqlite.addCSourceFile(.{ + .file = sqlite_amalgamation.path("sqlite3.c"), + .flags = flags.items, + }); // Tests const tests = b.addTest(.{ @@ -88,7 +95,10 @@ pub fn build(b: *std.Build) void { }), }); - tests.root_module.addCSourceFile(.{ .file = sqlite_amalgamation.path("sqlite3.c"), .flags = flags.items }); + tests.root_module.addCSourceFile(.{ + .file = sqlite_amalgamation.path("sqlite3.c"), + .flags = flags.items, + }); const run_tests = b.addRunArtifact(tests); diff --git a/build.zig.zon b/build.zig.zon index 112bfe4..1d7dd87 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -9,5 +9,9 @@ .url = "https://sqlite.org/2026/sqlite-amalgamation-3530100.zip", .hash = "N-V-__8AAK_4rQDqNybRFADVHf986hCbR9ln5ez1iWpmBV5L", }, + .translate_c = .{ + .url = "git+https://codeberg.org/ziglang/translate-c#d67f0a5821b0c5ad16f60c425ad2af3499e7995f", + .hash = "translate_c-0.0.0-Q_BUWho9BwAx1Nyc_gDzXBjXZg62qETbgze15f50x29Y", + }, }, } diff --git a/src/sqlite.zig b/src/sqlite.zig index e93f28d..5983f5d 100644 --- a/src/sqlite.zig +++ b/src/sqlite.zig @@ -120,8 +120,8 @@ pub fn Statement(comptime Params: type, comptime Result: type) type { const Self = @This(); ptr: ?*c.sqlite3_stmt = null, - param_index_map: [param_count]c_int = .{placeholder} ** param_count, - column_index_map: [column_count]c_int = .{placeholder} ** column_count, + param_index_map: [param_count]c_int = @splat(placeholder), + column_index_map: [column_count]c_int = @splat(placeholder), pub fn prepare(db: Database, sql: []const u8) !Self { var stmt = Self{}; @@ -453,21 +453,41 @@ const Binding = struct { } }; - field: std.builtin.Type.StructField, + /// This is pulled from builtin.zig/lang.zig in the std library since they + /// are moving towards using a struct of arrays pattern in 0.17.0. + /// + /// Alignment and comptime status are not read so I dropped that field. + const StructField = struct { + name: [:0]const u8, + type: type, + /// The type of the default value is the type of this struct field, which + /// is the value of the `type` field in this struct. However there is no + /// way to refer to that type here, so we use `*const anyopaque`. + /// See also: `defaultValue`. + default_value_ptr: ?*const anyopaque, + }; + + field: StructField, type: Type, nullable: bool, default_value_ptr: ?*const anyopaque, - pub fn parseStruct(comptime info: std.builtin.Type.Struct) [info.fields.len]Binding { - var bindings: [info.fields.len]Binding = undefined; - inline for (info.fields, 0..) |field, i| { + pub fn parseStruct(comptime info: std.builtin.Type.Struct) [info.field_names.len]Binding { + var bindings: [info.field_names.len]Binding = undefined; + inline for (0..info.field_names.len) |i| { + const field = StructField{ + .name = info.field_names[i], + .type = info.field_types[i], + .default_value_ptr = info.field_attrs[i].default_value_ptr, + }; + bindings[i] = parseField(field); } return bindings; } - pub fn parseField(comptime field: std.builtin.Type.StructField) Binding { + pub fn parseField(comptime field: StructField) Binding { return switch (@typeInfo(field.type)) { .optional => |field_type| Binding{ .field = field, diff --git a/src/test.zig b/src/test.zig index 3b95362..15457c1 100644 --- a/src/test.zig +++ b/src/test.zig @@ -149,7 +149,12 @@ test "deserialize" { // Construct a CWD-relative path for sqlite to open var path_buf: [std.Io.Dir.max_path_bytes]u8 = undefined; - const db_path = std.fmt.bufPrintZ(&path_buf, ".zig-cache/tmp/{s}/db.sqlite", .{&tmp.sub_path}) catch @panic("path too long"); + const db_path = std.fmt.bufPrintSentinel( + &path_buf, + ".zig-cache/tmp/{s}/db.sqlite", + .{&tmp.sub_path}, + 0, + ) catch @panic("path too long"); const db1 = try sqlite.Database.open(.{ .path = db_path }); defer db1.close(); @@ -214,4 +219,3 @@ test "errmsg" { \\near "FJDKLSFJDKSL": syntax error , std.mem.span(errmsg)); } -