lib: lib.Struct can convert packed structs to extern structs

This commit is contained in:
Mitchell Hashimoto
2026-03-14 14:20:23 -07:00
parent b5fb7ecaaa
commit 4e494ccd68

View File

@@ -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));
}