diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-10 21:51:57 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-10 21:51:57 +0300 |
| commit | 425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch) | |
| tree | e52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/src/lib/allocator/wasm.zig | |
| parent | 90e947a6e26e02f10ec7f1694c4eb5b78a86406b (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.zig | 98 |
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); +} |
