tigerbeetle-node 0.11.6 → 0.11.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/.client.node.sha256 +1 -1
  2. package/package.json +1 -1
  3. package/src/tigerbeetle/scripts/benchmark.bat +1 -2
  4. package/src/tigerbeetle/scripts/benchmark.sh +1 -2
  5. package/src/tigerbeetle/scripts/install.bat +7 -0
  6. package/src/tigerbeetle/scripts/install.sh +2 -3
  7. package/src/tigerbeetle/src/benchmark.zig +3 -3
  8. package/src/tigerbeetle/src/ewah.zig +6 -5
  9. package/src/tigerbeetle/src/ewah_fuzz.zig +1 -1
  10. package/src/tigerbeetle/src/io/darwin.zig +19 -0
  11. package/src/tigerbeetle/src/io/linux.zig +8 -0
  12. package/src/tigerbeetle/src/io/windows.zig +20 -2
  13. package/src/tigerbeetle/src/iops.zig +7 -1
  14. package/src/tigerbeetle/src/lsm/compaction.zig +18 -29
  15. package/src/tigerbeetle/src/lsm/forest_fuzz.zig +9 -5
  16. package/src/tigerbeetle/src/lsm/grid.zig +267 -267
  17. package/src/tigerbeetle/src/lsm/level_iterator.zig +18 -1
  18. package/src/tigerbeetle/src/lsm/manifest.zig +29 -1
  19. package/src/tigerbeetle/src/lsm/manifest_log.zig +5 -5
  20. package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +2 -2
  21. package/src/tigerbeetle/src/lsm/set_associative_cache.zig +26 -70
  22. package/src/tigerbeetle/src/lsm/table.zig +42 -0
  23. package/src/tigerbeetle/src/lsm/table_iterator.zig +27 -0
  24. package/src/tigerbeetle/src/lsm/table_mutable.zig +1 -1
  25. package/src/tigerbeetle/src/lsm/test.zig +2 -3
  26. package/src/tigerbeetle/src/lsm/tree.zig +27 -6
  27. package/src/tigerbeetle/src/lsm/tree_fuzz.zig +1 -1
  28. package/src/tigerbeetle/src/simulator.zig +0 -5
  29. package/src/tigerbeetle/src/storage.zig +58 -6
  30. package/src/tigerbeetle/src/test/cluster.zig +3 -0
  31. package/src/tigerbeetle/src/test/state_checker.zig +1 -1
  32. package/src/tigerbeetle/src/test/storage.zig +22 -1
  33. package/src/tigerbeetle/src/tracer.zig +50 -28
  34. package/src/tigerbeetle/src/unit_tests.zig +9 -4
  35. package/src/tigerbeetle/src/vopr.zig +4 -4
  36. package/src/tigerbeetle/src/vsr/journal.zig +153 -93
  37. package/src/tigerbeetle/src/vsr/replica.zig +10 -20
  38. package/src/tigerbeetle/src/vsr/superblock.zig +19 -16
  39. package/src/tigerbeetle/src/vsr/superblock_free_set.zig +114 -93
  40. package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +1 -1
  41. package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +1 -3
  42. package/src/tigerbeetle/src/vsr.zig +55 -8
  43. package/src/tigerbeetle/src/c/tb_client/context.zig +0 -304
  44. package/src/tigerbeetle/src/c/tb_client/echo_client.zig +0 -108
  45. package/src/tigerbeetle/src/c/tb_client/packet.zig +0 -80
  46. package/src/tigerbeetle/src/c/tb_client/signal.zig +0 -286
  47. package/src/tigerbeetle/src/c/tb_client/thread.zig +0 -88
  48. package/src/tigerbeetle/src/c/tb_client.h +0 -220
  49. package/src/tigerbeetle/src/c/tb_client.zig +0 -177
  50. package/src/tigerbeetle/src/c/tb_client_header.zig +0 -218
  51. package/src/tigerbeetle/src/c/tb_client_header_test.zig +0 -135
  52. package/src/tigerbeetle/src/c/test.zig +0 -371
  53. package/src/tigerbeetle/src/cli.zig +0 -399
  54. package/src/tigerbeetle/src/main.zig +0 -242
@@ -1,177 +0,0 @@
1
- const std = @import("std");
2
- const builtin = @import("builtin");
3
-
4
- pub const tb_packet_t = @import("tb_client/packet.zig").Packet;
5
- pub const tb_packet_list_t = tb_packet_t.List;
6
- pub const tb_packet_status_t = tb_packet_t.Status;
7
-
8
- pub const tb_client_t = *anyopaque;
9
- pub const tb_status_t = enum(c_int) {
10
- success = 0,
11
- unexpected,
12
- out_of_memory,
13
- address_invalid,
14
- address_limit_exceeded,
15
- packets_count_invalid,
16
- system_resources,
17
- network_subsystem,
18
- };
19
-
20
- pub const tb_operation_t = StateMachine.Operation;
21
- pub const tb_completion_t = fn (
22
- context: usize,
23
- client: tb_client_t,
24
- packet: *tb_packet_t,
25
- result_ptr: ?[*]const u8,
26
- result_len: u32,
27
- ) callconv(.C) void;
28
-
29
- const constants = @import("../constants.zig");
30
- const Storage = @import("../storage.zig").Storage;
31
- const MessageBus = @import("../message_bus.zig").MessageBusClient;
32
- const StateMachine = @import("../state_machine.zig").StateMachineType(Storage, .{
33
- .message_body_size_max = constants.message_body_size_max,
34
- });
35
-
36
- const ContextType = @import("tb_client/context.zig").ContextType;
37
- const ContextImplementation = @import("tb_client/context.zig").ContextImplementation;
38
-
39
- const DefaultContext = blk: {
40
- const Client = @import("../vsr/client.zig").Client(StateMachine, MessageBus);
41
- break :blk ContextType(Client);
42
- };
43
-
44
- const TestingContext = blk: {
45
- const EchoClient = @import("tb_client/echo_client.zig").EchoClient(StateMachine, MessageBus);
46
- break :blk ContextType(EchoClient);
47
- };
48
-
49
- pub fn context_to_client(implementation: *ContextImplementation) tb_client_t {
50
- return @ptrCast(tb_client_t, implementation);
51
- }
52
-
53
- fn client_to_context(tb_client: tb_client_t) *ContextImplementation {
54
- return @ptrCast(*ContextImplementation, @alignCast(@alignOf(ContextImplementation), tb_client));
55
- }
56
-
57
- // Only export the functions if we're compiling libtb_client.
58
- // If it's only being imported by another zig file, then exporting the functions
59
- // will force them to be evaluated/codegen/linked and trigger unexpected comptime paths.
60
- comptime {
61
- if (builtin.link_libc) {
62
- @export(tb_client_init, .{ .name = "tb_client_init", .linkage = .Strong });
63
- @export(tb_client_init_echo, .{ .name = "tb_client_init_echo", .linkage = .Strong });
64
- }
65
- }
66
-
67
- pub fn tb_client_init(
68
- out_client: *tb_client_t,
69
- out_packets: *tb_packet_list_t,
70
- cluster_id: u32,
71
- addresses_ptr: [*:0]const u8,
72
- addresses_len: u32,
73
- packets_count: u32,
74
- on_completion_ctx: usize,
75
- on_completion_fn: tb_completion_t,
76
- ) callconv(.C) tb_status_t {
77
- return init(
78
- DefaultContext,
79
- out_client,
80
- out_packets,
81
- cluster_id,
82
- addresses_ptr,
83
- addresses_len,
84
- packets_count,
85
- on_completion_ctx,
86
- on_completion_fn,
87
- );
88
- }
89
-
90
- pub fn tb_client_init_echo(
91
- out_client: *tb_client_t,
92
- out_packets: *tb_packet_list_t,
93
- cluster_id: u32,
94
- addresses_ptr: [*:0]const u8,
95
- addresses_len: u32,
96
- packets_count: u32,
97
- on_completion_ctx: usize,
98
- on_completion_fn: tb_completion_t,
99
- ) callconv(.C) tb_status_t {
100
- return init(
101
- TestingContext,
102
- out_client,
103
- out_packets,
104
- cluster_id,
105
- addresses_ptr,
106
- addresses_len,
107
- packets_count,
108
- on_completion_ctx,
109
- on_completion_fn,
110
- );
111
- }
112
-
113
- fn init(
114
- comptime Context: type,
115
- out_client: *tb_client_t,
116
- out_packets: *tb_packet_list_t,
117
- cluster_id: u32,
118
- addresses_ptr: [*:0]const u8,
119
- addresses_len: u32,
120
- packets_count: u32,
121
- on_completion_ctx: usize,
122
- on_completion_fn: tb_completion_t,
123
- ) tb_status_t {
124
- // Pick the most suitable allocator for the platform.
125
- const allocator = if (builtin.is_test)
126
- std.testing.allocator
127
- else if (builtin.link_libc)
128
- std.heap.c_allocator
129
- else if (builtin.target.os.tag == .windows)
130
- (struct {
131
- var gpa = std.heap.HeapAllocator.init();
132
- }).gpa.allocator()
133
- else
134
- @compileError("tb_client must be built with libc");
135
-
136
- const addresses = @ptrCast([*]const u8, addresses_ptr)[0..addresses_len];
137
- const context = Context.init(
138
- allocator,
139
- cluster_id,
140
- addresses,
141
- packets_count,
142
- on_completion_ctx,
143
- on_completion_fn,
144
- ) catch |err| switch (err) {
145
- error.Unexpected => return .unexpected,
146
- error.OutOfMemory => return .out_of_memory,
147
- error.AddressInvalid => return .address_invalid,
148
- error.AddressLimitExceeded => return .address_limit_exceeded,
149
- error.PacketsCountInvalid => return .packets_count_invalid,
150
- error.SystemResources => return .system_resources,
151
- error.NetworkSubsystemFailed => return .network_subsystem,
152
- };
153
-
154
- out_client.* = context_to_client(&context.implementation);
155
- var list = tb_packet_list_t{};
156
- for (context.packets) |*packet| {
157
- list.push(tb_packet_list_t.from(packet));
158
- }
159
-
160
- out_packets.* = list;
161
- return .success;
162
- }
163
-
164
- pub export fn tb_client_submit(
165
- client: tb_client_t,
166
- packets: *tb_packet_list_t,
167
- ) void {
168
- const context = client_to_context(client);
169
- (context.submit_fn)(context, packets);
170
- }
171
-
172
- pub export fn tb_client_deinit(
173
- client: tb_client_t,
174
- ) void {
175
- const context = client_to_context(client);
176
- (context.deinit_fn)(context);
177
- }
@@ -1,218 +0,0 @@
1
- const std = @import("std");
2
- const tb = @import("../tigerbeetle.zig");
3
- const tb_client = @import("tb_client.zig");
4
-
5
- const type_mappings = .{
6
- .{ tb.AccountFlags, "TB_ACCOUNT_FLAGS" },
7
- .{ tb.Account, "tb_account_t" },
8
- .{ tb.TransferFlags, "TB_TRANSFER_FLAGS" },
9
- .{ tb.Transfer, "tb_transfer_t" },
10
- .{ tb.CreateAccountResult, "TB_CREATE_ACCOUNT_RESULT" },
11
- .{ tb.CreateTransferResult, "TB_CREATE_TRANSFER_RESULT" },
12
- .{ tb.CreateAccountsResult, "tb_create_accounts_result_t" },
13
- .{ tb.CreateTransfersResult, "tb_create_transfers_result_t" },
14
- .{ tb_client.tb_operation_t, "TB_OPERATION" },
15
- .{ tb_client.tb_packet_status_t, "TB_PACKET_STATUS" },
16
- .{ tb_client.tb_packet_t, "tb_packet_t" },
17
- .{ tb_client.tb_packet_list_t, "tb_packet_list_t" },
18
- .{ tb_client.tb_client_t, "tb_client_t" },
19
- .{ tb_client.tb_status_t, "TB_STATUS" },
20
- };
21
-
22
- fn resolve_c_type(comptime Type: type) []const u8 {
23
- switch (@typeInfo(Type)) {
24
- .Array => |info| return resolve_c_type(info.child),
25
- .Enum => |info| return resolve_c_type(info.tag_type),
26
- .Struct => return resolve_c_type(std.meta.Int(.unsigned, @bitSizeOf(Type))),
27
- .Int => |info| {
28
- std.debug.assert(info.signedness == .unsigned);
29
- return switch (info.bits) {
30
- 8 => "uint8_t",
31
- 16 => "uint16_t",
32
- 32 => "uint32_t",
33
- 64 => "uint64_t",
34
- 128 => "tb_uint128_t",
35
- else => @compileError("invalid int type"),
36
- };
37
- },
38
- .Optional => |info| switch (@typeInfo(info.child)) {
39
- .Pointer => return resolve_c_type(info.child),
40
- else => @compileError("Unsupported optional type: " ++ @typeName(Type)),
41
- },
42
- .Pointer => |info| {
43
- std.debug.assert(info.size != .Slice);
44
- std.debug.assert(!info.is_allowzero);
45
-
46
- inline for (type_mappings) |type_mapping| {
47
- const ZigType = type_mapping[0];
48
- const c_name = type_mapping[1];
49
-
50
- if (info.child == ZigType) {
51
- const prefix = if (@typeInfo(ZigType) == .Struct) "struct " else "";
52
- return prefix ++ c_name ++ "*";
53
- }
54
- }
55
-
56
- return resolve_c_type(info.child) ++ "*";
57
- },
58
- .Void, .Opaque => return "void",
59
- else => @compileError("Unhandled type: " ++ @typeName(Type)),
60
- }
61
- }
62
-
63
- fn to_uppercase(comptime input: []const u8) []const u8 {
64
- comptime var output: [input.len]u8 = undefined;
65
- inline for (output) |*char, i| {
66
- char.* = input[i];
67
- char.* -= 32 * @as(u8, @boolToInt(char.* >= 'a' and char.* <= 'z'));
68
- }
69
- return &output;
70
- }
71
-
72
- fn emit_enum(
73
- buffer: *std.ArrayList(u8),
74
- comptime type_info: anytype,
75
- comptime c_name: []const u8,
76
- comptime value_fmt: []const u8,
77
- comptime skip_fields: []const []const u8,
78
- ) !void {
79
- var suffix_pos = std.mem.lastIndexOf(u8, c_name, "_").?;
80
- if (std.mem.count(u8, c_name, "_") == 1) suffix_pos = c_name.len;
81
-
82
- try buffer.writer().print("typedef enum {s} {{\n", .{c_name});
83
-
84
- inline for (type_info.fields) |field, i| {
85
- comptime var skip = false;
86
- inline for (skip_fields) |sf| {
87
- skip = skip or comptime std.mem.eql(u8, sf, field.name);
88
- }
89
-
90
- if (!skip) {
91
- try buffer.writer().print(" {s}_{s} = " ++ value_fmt ++ ",\n", .{
92
- c_name[0..suffix_pos],
93
- to_uppercase(field.name),
94
- i,
95
- });
96
- }
97
- }
98
-
99
- try buffer.writer().print("}} {s};\n\n", .{c_name});
100
- }
101
-
102
- fn emit_struct(
103
- buffer: *std.ArrayList(u8),
104
- comptime type_info: anytype,
105
- comptime c_name: []const u8,
106
- ) !void {
107
- try buffer.writer().print("typedef struct {s} {{\n", .{c_name});
108
-
109
- inline for (type_info.fields) |field| {
110
- try buffer.writer().print(" {s} {s}", .{
111
- resolve_c_type(field.field_type),
112
- field.name,
113
- });
114
-
115
- switch (@typeInfo(field.field_type)) {
116
- .Array => |array| try buffer.writer().print("[{d}]", .{array.len}),
117
- else => {},
118
- }
119
-
120
- try buffer.writer().print(";\n", .{});
121
- }
122
-
123
- try buffer.writer().print("}} {s};\n\n", .{c_name});
124
- }
125
-
126
- pub fn main() !void {
127
- @setEvalBranchQuota(100_000);
128
-
129
- var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
130
- defer arena.deinit();
131
- const allocator = arena.allocator();
132
-
133
- var buffer = std.ArrayList(u8).init(allocator);
134
- try buffer.writer().print(
135
- \\ //////////////////////////////////////////////////////////
136
- \\ // This file was auto-generated by tb_client_header.zig //
137
- \\ // Do not manually modify. //
138
- \\ //////////////////////////////////////////////////////////
139
- \\
140
- \\#ifndef TB_CLIENT_H
141
- \\#define TB_CLIENT_H
142
- \\
143
- \\#include <stddef.h>
144
- \\#include <stdint.h>
145
- \\#include <stdbool.h>
146
- \\
147
- \\typedef __uint128_t tb_uint128_t;
148
- \\
149
- \\
150
- , .{});
151
-
152
- // Emit C type declarations.
153
- inline for (type_mappings) |type_mapping| {
154
- const ZigType = type_mapping[0];
155
- const c_name = type_mapping[1];
156
-
157
- switch (@typeInfo(ZigType)) {
158
- .Struct => |info| switch (info.layout) {
159
- .Auto => @compileError("Invalid C struct type: " ++ @typeName(ZigType)),
160
- .Packed => try emit_enum(&buffer, info, c_name, "1 << {d}", &.{"padding"}),
161
- .Extern => try emit_struct(&buffer, info, c_name),
162
- },
163
- .Enum => |info| {
164
- comptime var skip: []const []const u8 = &.{};
165
- if (ZigType == tb_client.tb_operation_t) {
166
- skip = &.{ "reserved", "root", "register" };
167
- }
168
-
169
- try emit_enum(&buffer, info, c_name, "{d}", skip);
170
- },
171
- else => try buffer.writer().print("typedef {s} {s}; \n\n", .{
172
- resolve_c_type(ZigType),
173
- c_name,
174
- }),
175
- }
176
- }
177
-
178
- // Emit C function declarations.
179
- // TODO: use `std.meta.declaractions` and generate with pub + export functions.
180
- // Zig 0.9.1 has `decl.data.Fn.arg_names` but it's currently/incorrectly a zero-sized slice.
181
- try buffer.writer().print(
182
- \\TB_STATUS tb_client_init(
183
- \\ tb_client_t* out_client,
184
- \\ struct tb_packet_list_t* out_packets,
185
- \\ uint32_t cluster_id,
186
- \\ const char* address_ptr,
187
- \\ uint32_t address_len,
188
- \\ uint32_t packets_count,
189
- \\ uintptr_t on_completion_ctx,
190
- \\ void (*on_completion_fn)(uintptr_t, tb_client_t, tb_packet_t*, const uint8_t*, uint32_t)
191
- \\);
192
- \\
193
- \\TB_STATUS tb_client_init_echo(
194
- \\ tb_client_t* out_client,
195
- \\ struct tb_packet_list_t* out_packets,
196
- \\ uint32_t cluster_id,
197
- \\ const char* address_ptr,
198
- \\ uint32_t address_len,
199
- \\ uint32_t packets_count,
200
- \\ uintptr_t on_completion_ctx,
201
- \\ void (*on_completion_fn)(uintptr_t, tb_client_t, tb_packet_t*, const uint8_t*, uint32_t)
202
- \\);
203
- \\
204
- \\void tb_client_submit(
205
- \\ tb_client_t client,
206
- \\ struct tb_packet_list_t* packets
207
- \\);
208
- \\
209
- \\void tb_client_deinit(
210
- \\ tb_client_t client
211
- \\);
212
- \\
213
- \\
214
- , .{});
215
-
216
- try buffer.writer().print("#endif // TB_CLIENT_H\n\n", .{});
217
- try std.fs.cwd().writeFile("src/c/tb_client.h", buffer.items);
218
- }
@@ -1,135 +0,0 @@
1
- const std = @import("std");
2
- const assert = std.debug.assert;
3
-
4
- const tb = @import("../tigerbeetle.zig");
5
- const tb_client = @import("./tb_client.zig");
6
- const c = @cImport(@cInclude("tb_client.h"));
7
-
8
- fn to_lowercase(comptime input: []const u8) []const u8 {
9
- comptime var lowercase: [input.len]u8 = undefined;
10
- inline for (input) |char, i| {
11
- const is_uppercase = (char >= 'A') and (char <= 'Z');
12
- lowercase[i] = char + (@as(u8, @boolToInt(is_uppercase)) * 32);
13
- }
14
- return &lowercase;
15
- }
16
-
17
- fn to_uppercase(comptime input: []const u8) []const u8 {
18
- comptime var uppercase: [input.len]u8 = undefined;
19
- inline for (input) |char, i| {
20
- const is_lowercase = (char >= 'a') and (char <= 'z');
21
- uppercase[i] = char - (@as(u8, @boolToInt(is_lowercase)) * 32);
22
- }
23
- return &uppercase;
24
- }
25
-
26
- fn to_snakecase(comptime input: []const u8) []const u8 {
27
- comptime var output: []const u8 = &.{};
28
- inline for (input) |char, i| {
29
- const is_uppercase = (char >= 'A') and (char <= 'Z');
30
- if (is_uppercase and i > 0) output = "_" ++ output;
31
- output = output ++ &[_]u8{char};
32
- }
33
- return output;
34
- }
35
-
36
- test "valid tb_client.h" {
37
- @setEvalBranchQuota(10_000);
38
-
39
- inline for (.{
40
- .{ tb.Account, "tb_account_t" },
41
- .{ tb.Transfer, "tb_transfer_t" },
42
- .{ tb.AccountFlags, "TB_ACCOUNT_FLAGS" },
43
- .{ tb.TransferFlags, "TB_TRANSFER_FLAGS" },
44
- .{ tb.CreateAccountResult, "TB_CREATE_ACCOUNT_RESULT" },
45
- .{ tb.CreateTransferResult, "TB_CREATE_TRANSFER_RESULT" },
46
- .{ tb.CreateAccountsResult, "tb_create_accounts_result_t" },
47
- .{ tb.CreateTransfersResult, "tb_create_transfers_result_t" },
48
-
49
- .{ u128, "tb_uint128_t" },
50
- .{ tb_client.tb_status_t, "TB_STATUS" },
51
- .{ tb_client.tb_client_t, "tb_client_t" },
52
- .{ tb_client.tb_packet_t, "tb_packet_t" },
53
- .{ tb_client.tb_packet_list_t, "tb_packet_list_t" },
54
- .{ tb_client.tb_packet_status_t, "TB_PACKET_STATUS" },
55
- }) |c_export| {
56
- const ty: type = c_export[0];
57
- const c_type_name = @as([]const u8, c_export[1]);
58
- const c_type: type = @field(c, c_type_name);
59
-
60
- switch (@typeInfo(ty)) {
61
- .Int => comptime assert(ty == c_type),
62
- .Pointer => comptime assert(@sizeOf(ty) == @sizeOf(c_type)),
63
- .Enum => {
64
- const prefix_offset = comptime std.mem.lastIndexOf(u8, c_type_name, "_").?;
65
- comptime var c_enum_prefix: []const u8 = c_type_name[0 .. prefix_offset + 1];
66
- comptime assert(c_type == c_uint);
67
-
68
- // TB_STATUS is a special case in naming
69
- if (comptime std.mem.eql(u8, c_type_name, "TB_STATUS")) {
70
- c_enum_prefix = c_type_name ++ "_";
71
- }
72
-
73
- // Compare the enum int values in C to the enum int values in Zig.
74
- inline for (std.meta.fields(ty)) |field| {
75
- const c_enum_field = comptime to_uppercase(to_snakecase(field.name));
76
- const c_value = @field(c, c_enum_prefix ++ c_enum_field);
77
-
78
- const zig_value = @enumToInt(@field(ty, field.name));
79
- comptime assert(zig_value == c_value);
80
- }
81
- },
82
- .Struct => |type_info| switch (type_info.layout) {
83
- .Auto => @compileError("struct must be extern or packed to be used in C"),
84
- .Packed => {
85
- const prefix_offset = comptime std.mem.lastIndexOf(u8, c_type_name, "_").?;
86
- const c_enum_prefix = c_type_name[0 .. prefix_offset + 1];
87
- comptime assert(c_type == c_uint);
88
-
89
- inline for (std.meta.fields(ty)) |field| {
90
- if (comptime !std.mem.eql(u8, field.name, "padding")) {
91
- // Get the bit value in the C enum.
92
- const c_enum_field = comptime to_uppercase(to_snakecase(field.name));
93
- const c_value = @field(c, c_enum_prefix ++ c_enum_field);
94
-
95
- // Compare the bit value to the packed struct's field.
96
- comptime var instance = std.mem.zeroes(ty);
97
- @field(instance, field.name) = true;
98
- comptime assert(@bitCast(u16, instance) == c_value);
99
- }
100
- }
101
- },
102
- .Extern => {
103
- // Ensure structs are effectively the same.
104
- comptime assert(@sizeOf(ty) == @sizeOf(c_type));
105
- comptime assert(@alignOf(ty) == @alignOf(c_type));
106
-
107
- inline for (std.meta.fields(ty)) |field| {
108
- // In C, packed structs and enums are replaced with integers.
109
- comptime var field_type = field.field_type;
110
- switch (@typeInfo(field_type)) {
111
- .Struct => |info| {
112
- comptime assert(info.layout == .Packed);
113
- comptime assert(@sizeOf(field_type) <= @sizeOf(u128));
114
- field_type = std.meta.Int(.unsigned, @bitSizeOf(field_type));
115
- },
116
- .Enum => |info| field_type = info.tag_type,
117
- else => {},
118
- }
119
-
120
- // In C, pointers are opaque so we compare only the field sizes,
121
- comptime var c_field_type = @TypeOf(@field(@as(c_type, undefined), field.name));
122
- switch (@typeInfo(c_field_type)) {
123
- .Pointer => |info| {
124
- comptime assert(info.size == .C);
125
- comptime assert(@sizeOf(c_field_type) == @sizeOf(field_type));
126
- },
127
- else => comptime assert(c_field_type == field_type),
128
- }
129
- }
130
- },
131
- },
132
- else => |i| @compileLog("TODO", i),
133
- }
134
- }
135
- }