aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/lib/struct.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/lib/struct.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/lib/struct.zig')
-rw-r--r--vendor/libghostty-vt/src/lib/struct.zig105
1 files changed, 105 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/lib/struct.zig b/vendor/libghostty-vt/src/lib/struct.zig
new file mode 100644
index 00000000..bbf07ece
--- /dev/null
+++ b/vendor/libghostty-vt/src/lib/struct.zig
@@ -0,0 +1,105 @@
+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,
+) type {
+ return switch (target) {
+ .zig => Zig,
+ .c => c: {
+ const info = @typeInfo(Zig).@"struct";
+ var fields: [info.fields.len]std.builtin.Type.StructField = undefined;
+ for (info.fields, 0..) |field, i| {
+ fields[i] = .{
+ .name = field.name,
+ .type = field.type,
+ .default_value_ptr = field.default_value_ptr,
+ .is_comptime = field.is_comptime,
+ .alignment = if (field.alignment > 0) field.alignment else @alignOf(field.type),
+ };
+ }
+
+ break :c @Type(.{ .@"struct" = .{
+ .layout = .@"extern",
+ .fields = &fields,
+ .decls = &.{},
+ .is_tuple = info.is_tuple,
+ } });
+ },
+ };
+}
+
+/// Returns true if a struct of type `T` with size `size` can set
+/// field `field` (if it fits within the size). This is used for ABI
+/// compatibility for structs that have an explicit size field.
+pub fn sizedFieldFits(
+ comptime T: type,
+ size: usize,
+ comptime field: []const u8,
+) bool {
+ const offset = @offsetOf(T, field);
+ const field_size = @sizeOf(@FieldType(T, field));
+ return size >= offset + field_size;
+}
+
+test "sizedFieldFits boundary checks" {
+ const Sized = extern struct {
+ size: usize,
+ a: u8,
+ b: u32,
+ };
+
+ const size_required = @offsetOf(Sized, "size") + @sizeOf(@FieldType(Sized, "size"));
+ const a_required = @offsetOf(Sized, "a") + @sizeOf(@FieldType(Sized, "a"));
+ const b_required = @offsetOf(Sized, "b") + @sizeOf(@FieldType(Sized, "b"));
+
+ try testing.expect(sizedFieldFits(Sized, size_required, "size"));
+ try testing.expect(!sizedFieldFits(Sized, size_required - 1, "size"));
+
+ try testing.expect(sizedFieldFits(Sized, a_required, "a"));
+ try testing.expect(!sizedFieldFits(Sized, a_required - 1, "a"));
+
+ try testing.expect(sizedFieldFits(Sized, b_required, "b"));
+ try testing.expect(!sizedFieldFits(Sized, b_required - 1, "b"));
+}
+
+test "sizedFieldFits respects alignment padding" {
+ const Sized = extern struct {
+ size: usize,
+ a: u8,
+ b: u32,
+ };
+
+ const up_to_padding = @offsetOf(Sized, "b");
+ try testing.expect(sizedFieldFits(Sized, up_to_padding, "a"));
+ try testing.expect(!sizedFieldFits(Sized, up_to_padding, "b"));
+}
+
+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));
+}