diff --git a/src/platform.zig b/src/platform.zig index 65c6539e..8d242ffb 100644 --- a/src/platform.zig +++ b/src/platform.zig @@ -1,7 +1,41 @@ const builtin = @import("builtin"); -const Platform = if (builtin.cpu.arch == .wasm32) @import("platform/wasm.zig") else @import("platform/native.zig"); +const Platform = if (builtin.cpu.arch == .wasm32) + Interface(@import("platform/wasm.zig")) +else + Interface(@import("platform/native.zig")); -// TODO: verify declarations and its signatures pub const Type = Platform.Platform; pub const BackingTimerType = Platform.BackingTimer; + +/// Verifies that a Platform implementation exposes the expected function declarations. +fn Interface(comptime T: type) type { + assertHasDecl(T, "Platform"); + assertHasDecl(T, "BackingTimer"); + assertHasDecl(T.Platform, "init"); + assertHasDecl(T.Platform, "deinit"); + assertHasDecl(T.Platform, "setOptions"); + assertHasDecl(T.Platform, "close"); + assertHasDecl(T.Platform, "setWaitEvent"); + assertHasDecl(T.Platform, "getFramebufferSize"); + assertHasDecl(T.Platform, "getWindowSize"); + assertHasDecl(T.Platform, "setMouseCursor"); + assertHasDecl(T.Platform, "hasEvent"); + assertHasDecl(T.Platform, "pollEvent"); + assertHasDecl(T.BackingTimer, "start"); + assertHasDecl(T.BackingTimer, "read"); + assertHasDecl(T.BackingTimer, "reset"); + assertHasDecl(T.BackingTimer, "lap"); + + return T; +} + +fn assertDecl(comptime T: anytype, comptime name: []const u8, comptime Decl: type) void { + assertHasDecl(T, name); + const FoundDecl = @TypeOf(@field(T, name)); + if (FoundDecl != Decl) @compileError("Platform field '" ++ name ++ "'\n\texpected type: " ++ @typeName(Decl) ++ "\n\t found type: " ++ @typeName(FoundDecl)); +} + +fn assertHasDecl(comptime T: anytype, comptime name: []const u8) void { + if (!@hasDecl(T, name)) @compileError("Platform missing declaration: " ++ name); +} diff --git a/src/platform/wasm.zig b/src/platform/wasm.zig index fa0cc2a2..4d515fc4 100644 --- a/src/platform/wasm.zig +++ b/src/platform/wasm.zig @@ -43,6 +43,7 @@ pub const CanvasId = u32; pub const Platform = struct { id: CanvasId, selector_id: []const u8, + allocator: std.mem.Allocator, last_window_size: structs.Size, last_framebuffer_size: structs.Size, @@ -57,6 +58,7 @@ pub const Platform = struct { var platform = Platform{ .id = id, .selector_id = try allocator.dupe(u8, selector[0 .. selector.len - @as(u32, if (selector[selector.len - 1] == 0) 1 else 0)]), + .allocator = allocator, .last_window_size = .{ .width = js.machCanvasGetWindowWidth(id), .height = js.machCanvasGetWindowHeight(id), @@ -85,6 +87,11 @@ pub const Platform = struct { return platform; } + pub fn deinit(platform: *Platform) void { + js.machCanvasDeinit(platform.id); + platform.allocator.free(platform.selector_id); + } + pub fn setOptions(platform: *Platform, options: structs.Options) !void { // NOTE: size limits do not exists on wasm js.machCanvasSetSize(platform.id, options.width, options.height); @@ -302,6 +309,7 @@ export fn wasmUpdate() void { export fn wasmDeinit() void { app.deinit(&core); + core.internal.deinit(); } pub const log_level = if (@hasDecl(App, "log_level")) App.log_level else std.log.default_level;