aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/lib/allocator/wasm.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-10 21:51:57 +0300
committerGitHub <noreply@github.com>2026-09-10 21:51:57 +0300
commit425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch)
treee52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/src/lib/allocator/wasm.zig
parent90e947a6e26e02f10ec7f1694c4eb5b78a86406b (diff)
chore: upgrade libghostty and preserve terminal behavior (#3906)
Diffstat (limited to 'vendor/libghostty-vt/src/lib/allocator/wasm.zig')
-rw-r--r--vendor/libghostty-vt/src/lib/allocator/wasm.zig98
1 files changed, 98 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/lib/allocator/wasm.zig b/vendor/libghostty-vt/src/lib/allocator/wasm.zig
new file mode 100644
index 00000000..22439103
--- /dev/null
+++ b/vendor/libghostty-vt/src/lib/allocator/wasm.zig
@@ -0,0 +1,98 @@
+//! Wasm allocation conveniences for caller-owned storage and opaque out slots.
+//!
+//! The primary use case for this is Wasm builds. Ghostty relies a lot on
+//! pointers to various types for ABI compatibility and creating those pointers
+//! in Wasm is tedious. This file contains the small set of functions exposed by
+//! the Wasm module without changing the API from the C library.
+//!
+//! Given these are convenience methods, they always use the default allocator.
+//! If a caller is using a custom allocator, they have the expertise to
+//! allocate these types manually using their custom allocator.
+
+const std = @import("std");
+const c_abi = @import("../c_abi.zig");
+
+// Get our default allocator at comptime since it is known.
+const default = @import("../allocator.zig").default;
+const alloc = default(null);
+const wasm_alignment: std.mem.Alignment = .fromByteUnits(c_abi.max_alignment);
+
+/// A nullable opaque C handle stored in a constructor out-parameter slot.
+pub const Opaque = ?*anyopaque;
+
+/// Allocate `len` bytes of uninitialized, caller-owned Wasm ABI storage.
+///
+/// The returned pointer is aligned for any fundamental C ABI type and must be
+/// released with `freeBytes` using the same `len`. Returns null when `len` is
+/// zero or allocation fails.
+pub fn allocBytes(len: usize) callconv(.c) ?[*]u8 {
+ if (len == 0) return null;
+ return alloc.rawAlloc(len, wasm_alignment, @returnAddress());
+}
+
+/// Release storage returned by `allocBytes`.
+///
+/// `len` must exactly match the allocation length. A null pointer is ignored.
+pub fn freeBytes(ptr: ?[*]u8, len: usize) callconv(.c) void {
+ const p = ptr orelse return;
+ if (len == 0) return;
+ alloc.rawFree(p[0..len], wasm_alignment, @returnAddress());
+}
+
+/// Allocate a null-initialized slot for an opaque constructor out-parameter.
+///
+/// The slot may be reused after each value is removed with `takeOpaque`. It
+/// must eventually be released with `freeOpaque`.
+pub fn allocOpaque() callconv(.c) ?*Opaque {
+ const ptr = allocBytes(@sizeOf(Opaque)) orelse return null;
+ const result: *Opaque = @ptrCast(@alignCast(ptr));
+ result.* = null;
+ return result;
+}
+
+/// Release a slot returned by `allocOpaque` without freeing its stored handle.
+///
+/// Call the handle's type-specific destructor before freeing a populated slot.
+/// A null slot pointer is ignored.
+pub fn freeOpaque(ptr: ?*Opaque) callconv(.c) void {
+ freeBytes(@ptrCast(ptr), @sizeOf(Opaque));
+}
+
+/// Remove and return the handle in an opaque out-parameter slot.
+///
+/// The slot is reset to null so it can be safely reused for another
+/// constructor. This does not free either the handle or the slot. Returns null
+/// when the slot pointer is null or the slot is empty.
+pub fn takeOpaque(ptr: ?*Opaque) callconv(.c) Opaque {
+ const p = ptr orelse return null;
+ const result = p.*;
+ p.* = null;
+ return result;
+}
+
+test "Wasm allocation" {
+ const ptr = allocBytes(1) orelse return error.OutOfMemory;
+ defer freeBytes(ptr, 1);
+
+ try std.testing.expectEqual(
+ @as(usize, 0),
+ @intFromPtr(ptr) % c_abi.max_alignment,
+ );
+ ptr[0] = 42;
+ try std.testing.expectEqual(@as(u8, 42), ptr[0]);
+
+ try std.testing.expect(allocBytes(0) == null);
+ freeBytes(null, 0);
+}
+
+test "opaque slots are initialized and reusable" {
+ const slot = allocOpaque() orelse return error.OutOfMemory;
+ defer freeOpaque(slot);
+
+ try std.testing.expect(takeOpaque(slot) == null);
+
+ var value: u8 = 42;
+ slot.* = &value;
+ try std.testing.expectEqual(@as(?*anyopaque, &value), takeOpaque(slot));
+ try std.testing.expect(takeOpaque(slot) == null);
+}