From 4e494ccd688cd44f92d010cdd6fa46412339f69e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 14 Mar 2026 14:20:23 -0700 Subject: [PATCH] lib: lib.Struct can convert packed structs to extern structs --- src/lib/struct.zig | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/lib/struct.zig b/src/lib/struct.zig index d494da2e6..134f6bebc 100644 --- a/src/lib/struct.zig +++ b/src/lib/struct.zig @@ -1,6 +1,17 @@ const std = @import("std"); +const testing = std.testing; const Target = @import("target.zig").Target; +/// Create a struct type that is C ABI compatible from a Zig struct type. +/// +/// When the target is `.zig`, the original struct type is returned as-is. +/// When the target is `.c`, the struct is recreated with an `extern` layout, +/// ensuring a stable, C-compatible memory layout. +/// +/// This handles packed structs by resolving zero alignments to the natural +/// alignment of each field's type, since extern structs require explicit +/// alignment. This means packed struct fields like `bool` will take up +/// their full size (1 byte) rather than being bit-packed. pub fn Struct( comptime target: Target, comptime Zig: type, @@ -16,7 +27,7 @@ pub fn Struct( .type = field.type, .default_value_ptr = field.default_value_ptr, .is_comptime = field.is_comptime, - .alignment = field.alignment, + .alignment = if (field.alignment > 0) field.alignment else @alignOf(field.type), }; } @@ -29,3 +40,20 @@ pub fn Struct( }, }; } + +test "packed struct converts to extern with full-size bools" { + const Packed = packed struct { + flag1: bool, + flag2: bool, + value: u8, + }; + + const C = Struct(.c, Packed); + const info = @typeInfo(C).@"struct"; + + try testing.expectEqual(.@"extern", info.layout); + try testing.expectEqual(@as(usize, 1), @sizeOf(@FieldType(C, "flag1"))); + try testing.expectEqual(@as(usize, 1), @sizeOf(@FieldType(C, "flag2"))); + try testing.expectEqual(@as(usize, 1), @sizeOf(@FieldType(C, "value"))); + try testing.expectEqual(@as(usize, 3), @sizeOf(C)); +}