From 3648d6b9c428864ddc7fa8292fba5be68e8b0db7 Mon Sep 17 00:00:00 2001 From: InKryption <59504965+InKryption@users.noreply.github.com> Date: Tue, 7 Dec 2021 05:52:15 +0100 Subject: [PATCH] glfw: Denormalize errors (#115) Closes hexops/mach#96 Co-authored-by: Stephen Gutekanst --- glfw/src/Cursor.zig | 13 +- glfw/src/Joystick.zig | 76 ++++++--- glfw/src/Monitor.zig | 78 ++++++--- glfw/src/Window.zig | 348 ++++++++++++++++++++++++++++------------- glfw/src/clipboard.zig | 12 +- glfw/src/errors.zig | 16 +- glfw/src/key.zig | 11 +- glfw/src/main.zig | 50 ++++-- glfw/src/opengl.zig | 24 ++- glfw/src/time.zig | 18 ++- glfw/src/vulkan.zig | 17 +- 11 files changed, 457 insertions(+), 206 deletions(-) diff --git a/glfw/src/Cursor.zig b/glfw/src/Cursor.zig index 96622433..0ad37cd1 100644 --- a/glfw/src/Cursor.zig +++ b/glfw/src/Cursor.zig @@ -60,12 +60,13 @@ pub const Shape = enum(isize) { /// @thread_safety This function must only be called from the main thread. /// /// see also: cursor_object, glfw.Cursor.destroy, glfw.Cursor.createStandard -pub inline fn create(image: Image, xhot: isize, yhot: isize) Error!Cursor { +pub inline fn create(image: Image, xhot: isize, yhot: isize) error{PlatformError}!Cursor { internal_debug.assertInitialized(); const img = image.toC(); const cursor = c.glfwCreateCursor(&img, @intCast(c_int, xhot), @intCast(c_int, yhot)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return Cursor{ .ptr = cursor.? }; @@ -80,11 +81,13 @@ pub inline fn create(image: Image, xhot: isize, yhot: isize) Error!Cursor { /// @thread_safety This function must only be called from the main thread. /// /// see also: cursor_object, glfwCreateCursor -pub inline fn createStandard(shape: Shape) Error!Cursor { +pub inline fn createStandard(shape: Shape) error{PlatformError}!Cursor { internal_debug.assertInitialized(); const cursor = c.glfwCreateStandardCursor(@intCast(c_int, @enumToInt(shape))); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return Cursor{ .ptr = cursor.? }; @@ -109,7 +112,7 @@ pub inline fn destroy(self: Cursor) void { internal_debug.assertInitialized(); c.glfwDestroyCursor(self.ptr); getError() catch |err| return switch (err) { - Error.PlatformError => std.log.debug("{}: was unable to destroy Cursor.\n", .{err}), + Error.PlatformError => std.log.err("mach/glfw: unable to destroy Cursor: {}\n", .{err}), else => unreachable, }; } diff --git a/glfw/src/Joystick.zig b/glfw/src/Joystick.zig index 6c87b39e..a9cff2c8 100644 --- a/glfw/src/Joystick.zig +++ b/glfw/src/Joystick.zig @@ -87,11 +87,13 @@ const GamepadState = extern struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: joystick -pub inline fn present(self: Joystick) Error!bool { +pub inline fn present(self: Joystick) error{PlatformError}!bool { internal_debug.assertInitialized(); const is_present = c.glfwJoystickPresent(@enumToInt(self.jid)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return is_present == c.GLFW_TRUE; @@ -117,12 +119,14 @@ pub inline fn present(self: Joystick) Error!bool { /// /// see also: joystick_axis /// Replaces `glfwGetJoystickPos`. -pub inline fn getAxes(self: Joystick) Error!?[]const f32 { +pub inline fn getAxes(self: Joystick) error{PlatformError}!?[]const f32 { internal_debug.assertInitialized(); var count: c_int = undefined; const axes = c.glfwGetJoystickAxes(@enumToInt(self.jid), &count); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; if (axes == null) return null; @@ -153,12 +157,14 @@ pub inline fn getAxes(self: Joystick) Error!?[]const f32 { /// @thread_safety This function must only be called from the main thread. /// /// see also: joystick_button -pub inline fn getButtons(self: Joystick) Error!?[]const u8 { +pub inline fn getButtons(self: Joystick) error{PlatformError}!?[]const u8 { internal_debug.assertInitialized(); var count: c_int = undefined; const buttons = c.glfwGetJoystickButtons(@enumToInt(self.jid), &count); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; if (buttons == null) return null; @@ -205,12 +211,14 @@ pub inline fn getButtons(self: Joystick) Error!?[]const u8 { /// @thread_safety This function must only be called from the main thread. /// /// see also: joystick_hat -pub inline fn getHats(self: Joystick) Error!?[]const Hat { +pub inline fn getHats(self: Joystick) error{PlatformError}!?[]const Hat { internal_debug.assertInitialized(); var count: c_int = undefined; const hats = c.glfwGetJoystickHats(@enumToInt(self.jid), &count); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; if (hats == null) return null; @@ -237,11 +245,13 @@ pub inline fn getHats(self: Joystick) Error!?[]const Hat { /// @thread_safety This function must only be called from the main thread. /// /// see also: joystick_name -pub inline fn getName(self: Joystick) Error!?[:0]const u8 { +pub inline fn getName(self: Joystick) error{PlatformError}!?[:0]const u8 { internal_debug.assertInitialized(); const name_opt = c.glfwGetJoystickName(@enumToInt(self.jid)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return if (name_opt) |name| @@ -277,11 +287,13 @@ pub inline fn getName(self: Joystick) Error!?[:0]const u8 { /// @thread_safety This function must only be called from the main thread. /// /// see also: gamepad -pub inline fn getGUID(self: Joystick) Error!?[:0]const u8 { +pub inline fn getGUID(self: Joystick) error{PlatformError}!?[:0]const u8 { internal_debug.assertInitialized(); const guid_opt = c.glfwGetJoystickGUID(@enumToInt(self.jid)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return if (guid_opt) |guid| @@ -303,7 +315,10 @@ pub inline fn getGUID(self: Joystick) Error!?[:0]const u8 { pub inline fn setUserPointer(self: Joystick, comptime T: type, pointer: *T) void { internal_debug.assertInitialized(); c.glfwSetJoystickUserPointer(@enumToInt(self.jid), @ptrCast(*c_void, pointer)); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } /// Returns the user pointer of the specified joystick. @@ -320,7 +335,10 @@ pub inline fn setUserPointer(self: Joystick, comptime T: type, pointer: *T) void pub inline fn getUserPointer(self: Joystick, comptime PointerType: type) ?PointerType { internal_debug.assertInitialized(); const ptr = c.glfwGetJoystickUserPointer(@enumToInt(self.jid)); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; if (ptr) |p| return @ptrCast(PointerType, @alignCast(@alignOf(std.meta.Child(PointerType)), p)); return null; } @@ -365,7 +383,10 @@ pub inline fn setCallback(callback: ?fn (joystick: Joystick, event: Event) void) internal_debug.assertInitialized(); _callback = callback; _ = if (_callback != null) c.glfwSetJoystickCallback(callbackWrapper) else c.glfwSetJoystickCallback(null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } /// Adds the specified SDL_GameControllerDB gamepad mappings. @@ -391,15 +412,16 @@ pub inline fn setCallback(callback: ?fn (joystick: Joystick, event: Event) void) /// /// /// @ingroup input -pub inline fn updateGamepadMappings(gamepad_mappings: [*:0]const u8) Error!void { +pub inline fn updateGamepadMappings(gamepad_mappings: [*:0]const u8) error{InvalidValue}!void { internal_debug.assertInitialized(); _ = c.glfwUpdateGamepadMappings(gamepad_mappings); getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, // TODO: Maybe return as 'ParseError' here? // TODO: Look into upstream proposal for GLFW to publicize // their Gamepad mappings parsing functions/interface // for a better error message in debug. - Error.InvalidValue => err, + Error.InvalidValue => @errSetCast(error{InvalidValue}, err), else => unreachable, }; } @@ -422,7 +444,11 @@ pub inline fn updateGamepadMappings(gamepad_mappings: [*:0]const u8) Error!void pub inline fn isGamepad(self: Joystick) bool { internal_debug.assertInitialized(); const is_gamepad = c.glfwJoystickIsGamepad(@enumToInt(self.jid)); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + else => unreachable, + }; return is_gamepad == c.GLFW_TRUE; } @@ -438,6 +464,8 @@ pub inline fn isGamepad(self: Joystick) bool { /// @return The UTF-8 encoded name of the gamepad, or null if the joystick is not present or does /// not have a mapping. /// +/// Possible errors include glfw.Error.NotInitialized and glfw.Error.InvalidEnum. +/// /// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it /// yourself. It is valid until the specified joystick is disconnected, the gamepad mappings are /// updated or the library is terminated. @@ -445,10 +473,12 @@ pub inline fn isGamepad(self: Joystick) bool { /// @thread_safety This function must only be called from the main thread. /// /// see also: gamepad, glfw.Joystick.isGamepad -pub inline fn getGamepadName(self: Joystick) Error!?[:0]const u8 { +pub inline fn getGamepadName(self: Joystick) ?[:0]const u8 { internal_debug.assertInitialized(); const name_opt = c.glfwGetGamepadName(@enumToInt(self.jid)); getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + Error.InvalidValue => unreachable, else => unreachable, }; return if (name_opt) |name| @@ -485,7 +515,11 @@ pub inline fn getGamepadState(self: Joystick) ?GamepadState { internal_debug.assertInitialized(); var state: GamepadState = undefined; const success = c.glfwGetGamepadState(@enumToInt(self.jid), @ptrCast(*c.GLFWgamepadstate, &state)); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + else => unreachable, + }; return if (success == c.GLFW_TRUE) state else null; } @@ -608,7 +642,7 @@ test "getGamepadName" { defer glfw.terminate(); const joystick = glfw.Joystick{ .jid = .one }; - _ = joystick.getGamepadName() catch |err| std.debug.print("failed to get gamepad name, joysticks not supported? error={}\n", .{err}); + _ = joystick.getGamepadName(); } test "getGamepadState" { diff --git a/glfw/src/Monitor.zig b/glfw/src/Monitor.zig index ee4200e5..415cfbc1 100644 --- a/glfw/src/Monitor.zig +++ b/glfw/src/Monitor.zig @@ -32,13 +32,14 @@ const Pos = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_properties -pub inline fn getPos(self: Monitor) Error!Pos { +pub inline fn getPos(self: Monitor) error{PlatformError}!Pos { internal_debug.assertInitialized(); var xpos: c_int = 0; var ypos: c_int = 0; c.glfwGetMonitorPos(self.handle, &xpos, &ypos); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return Pos{ .x = @intCast(usize, xpos), .y = @intCast(usize, ypos) }; @@ -64,7 +65,7 @@ const Workarea = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_workarea -pub inline fn getWorkarea(self: Monitor) Error!Workarea { +pub inline fn getWorkarea(self: Monitor) error{PlatformError}!Workarea { internal_debug.assertInitialized(); var xpos: c_int = 0; var ypos: c_int = 0; @@ -72,7 +73,8 @@ pub inline fn getWorkarea(self: Monitor) Error!Workarea { var height: c_int = 0; c.glfwGetMonitorWorkarea(self.handle, &xpos, &ypos, &width, &height); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return Workarea{ .x = @intCast(usize, xpos), .y = @intCast(usize, ypos), .width = @intCast(usize, width), .height = @intCast(usize, height) }; @@ -103,7 +105,10 @@ pub inline fn getPhysicalSize(self: Monitor) PhysicalSize { var width_mm: c_int = 0; var height_mm: c_int = 0; c.glfwGetMonitorPhysicalSize(self.handle, &width_mm, &height_mm); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; return PhysicalSize{ .width_mm = @intCast(usize, width_mm), .height_mm = @intCast(usize, height_mm) }; } @@ -130,13 +135,14 @@ const ContentScale = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_scale, glfw.Window.getContentScale -pub inline fn getContentScale(self: Monitor) Error!ContentScale { +pub inline fn getContentScale(self: Monitor) error{PlatformError}!ContentScale { internal_debug.assertInitialized(); var x_scale: f32 = 0; var y_scale: f32 = 0; c.glfwGetMonitorContentScale(self.handle, &x_scale, &y_scale); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return ContentScale{ .x_scale = @floatCast(f32, x_scale), .y_scale = @floatCast(f32, y_scale) }; @@ -159,7 +165,10 @@ pub inline fn getContentScale(self: Monitor) Error!ContentScale { pub inline fn getName(self: Monitor) [*:0]const u8 { internal_debug.assertInitialized(); const name = c.glfwGetMonitorName(self.handle); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; return name; } @@ -179,7 +188,10 @@ pub inline fn getName(self: Monitor) [*:0]const u8 { pub inline fn setUserPointer(self: Monitor, comptime T: type, ptr: *T) void { internal_debug.assertInitialized(); c.glfwSetMonitorUserPointer(self.handle, ptr); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } /// Returns the user pointer of the specified monitor. @@ -197,7 +209,10 @@ pub inline fn setUserPointer(self: Monitor, comptime T: type, ptr: *T) void { pub inline fn getUserPointer(self: Monitor, comptime T: type) ?*T { internal_debug.assertInitialized(); const ptr = c.glfwGetMonitorUserPointer(self.handle); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; if (ptr == null) return null; return @ptrCast(*T, @alignCast(@alignOf(T), ptr.?)); } @@ -215,12 +230,13 @@ pub inline fn getUserPointer(self: Monitor, comptime T: type) ?*T { /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_modes, glfw.Monitor.getVideoMode -pub inline fn getVideoModes(self: Monitor, allocator: mem.Allocator) Error![]VideoMode { +pub inline fn getVideoModes(self: Monitor, allocator: mem.Allocator) (mem.Allocator.Error || error{PlatformError})![]VideoMode { internal_debug.assertInitialized(); var count: c_int = 0; const modes = c.glfwGetVideoModes(self.handle, &count); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; @@ -243,11 +259,12 @@ pub inline fn getVideoModes(self: Monitor, allocator: mem.Allocator) Error![]Vid /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_modes, glfw.Monitor.getVideoModes -pub inline fn getVideoMode(self: Monitor) Error!VideoMode { +pub inline fn getVideoMode(self: Monitor) error{PlatformError}!VideoMode { internal_debug.assertInitialized(); const mode = c.glfwGetVideoMode(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return VideoMode{ .handle = mode.?.* }; @@ -272,7 +289,7 @@ pub inline fn getVideoMode(self: Monitor) Error!VideoMode { /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_gamma -pub inline fn setGamma(self: Monitor, gamma: f32) Error!void { +pub inline fn setGamma(self: Monitor, gamma: f32) error{PlatformError}!void { internal_debug.assertInitialized(); std.debug.assert(!std.math.isNan(gamma)); @@ -281,8 +298,9 @@ pub inline fn setGamma(self: Monitor, gamma: f32) Error!void { c.glfwSetGamma(self.handle, gamma); getError() catch |err| return switch (err) { - Error.InvalidValue => unreachable, // we assert that 'gamma' is a valid value, so this should be impossible - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidValue => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -302,11 +320,12 @@ pub inline fn setGamma(self: Monitor, gamma: f32) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_gamma -pub inline fn getGammaRamp(self: Monitor) Error!GammaRamp { +pub inline fn getGammaRamp(self: Monitor) error{PlatformError}!GammaRamp { internal_debug.assertInitialized(); const ramp = c.glfwGetGammaRamp(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return GammaRamp.fromC(ramp.*); @@ -337,11 +356,12 @@ pub inline fn getGammaRamp(self: Monitor) Error!GammaRamp { /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_gamma -pub inline fn setGammaRamp(self: Monitor, ramp: GammaRamp) Error!void { +pub inline fn setGammaRamp(self: Monitor, ramp: GammaRamp) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetGammaRamp(self.handle, &ramp.toC()); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -361,8 +381,10 @@ pub inline fn getAll(allocator: mem.Allocator) mem.Allocator.Error![]Monitor { internal_debug.assertInitialized(); var count: c_int = 0; const monitors = c.glfwGetMonitors(&count); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible - + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; const slice = try allocator.alloc(Monitor, @intCast(usize, count)); var i: usize = 0; while (i < count) : (i += 1) { @@ -384,7 +406,10 @@ pub inline fn getAll(allocator: mem.Allocator) mem.Allocator.Error![]Monitor { pub inline fn getPrimary() ?Monitor { internal_debug.assertInitialized(); const handle = c.glfwGetPrimaryMonitor(); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; if (handle == null) { return null; } @@ -445,7 +470,10 @@ pub inline fn setCallback(comptime Data: type, data: *Data, f: ?*const fn (monit callback_fn_ptr = null; callback_data_ptr = null; } - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } test "getAll" { diff --git a/glfw/src/Window.zig b/glfw/src/Window.zig index 77af9cc5..159aace7 100644 --- a/glfw/src/Window.zig +++ b/glfw/src/Window.zig @@ -32,7 +32,10 @@ pub inline fn from(handle: *c.GLFWwindow) mem.Allocator.Error!Window { if (ptr == null) { const internal = try std.heap.c_allocator.create(InternalUserPointer); c.glfwSetWindowUserPointer(handle, @ptrCast(*c_void, internal)); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } return Window{ .handle = handle }; } @@ -75,7 +78,10 @@ pub const InternalUserPointer = struct { inline fn defaultHints() void { internal_debug.assertInitialized(); c.glfwDefaultWindowHints(); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } /// Window hints @@ -278,7 +284,11 @@ pub const Hints = struct { else => unreachable, } - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + else => unreachable, + }; } } }; @@ -398,7 +408,14 @@ pub const Hints = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_creation, glfw.Window.destroy -pub inline fn create(width: usize, height: usize, title: [*:0]const u8, monitor: ?Monitor, share: ?Window, hints: Hints) Error!Window { +pub inline fn create( + width: usize, + height: usize, + title: [*:0]const u8, + monitor: ?Monitor, + share: ?Window, + hints: Hints, +) (mem.Allocator.Error || error{ APIUnavailable, VersionUnavailable, FormatUnavailable, PlatformError })!Window { internal_debug.assertInitialized(); const ignore_hints_struct = if (comptime @import("builtin").is_test) testing_ignore_window_hints_struct else false; if (!ignore_hints_struct) hints.set(); @@ -413,12 +430,14 @@ pub inline fn create(width: usize, height: usize, title: [*:0]const u8, monitor: ); getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, Error.InvalidValue => unreachable, Error.APIUnavailable, Error.VersionUnavailable, Error.FormatUnavailable, Error.PlatformError, - => err, + => @errSetCast(error{ APIUnavailable, VersionUnavailable, FormatUnavailable, PlatformError }, err), else => unreachable, }; @@ -455,6 +474,7 @@ pub inline fn destroy(self: Window) void { // Zig, so by returning an error we'd make it harder to destroy the window properly. So we differ // from GLFW here: we discard any potential error from this operation. getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, Error.PlatformError => std.log.debug("{}: was unable to destroy Window.\n", .{err}), else => unreachable, }; @@ -470,7 +490,10 @@ pub inline fn destroy(self: Window) void { pub inline fn shouldClose(self: Window) bool { internal_debug.assertInitialized(); const flag = c.glfwWindowShouldClose(self.handle); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; return flag == c.GLFW_TRUE; } @@ -489,7 +512,10 @@ pub inline fn setShouldClose(self: Window, value: bool) void { internal_debug.assertInitialized(); const boolean = if (value) c.GLFW_TRUE else c.GLFW_FALSE; c.glfwSetWindowShouldClose(self.handle, boolean); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } /// Sets the UTF-8 encoded title of the specified window. @@ -503,11 +529,12 @@ pub inline fn setShouldClose(self: Window, value: bool) void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_title -pub inline fn setTitle(self: Window, title: [*:0]const u8) Error!void { +pub inline fn setTitle(self: Window, title: [*:0]const u8) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetWindowTitle(self.handle, title); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -540,7 +567,7 @@ pub inline fn setTitle(self: Window, title: [*:0]const u8) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_icon -pub inline fn setIcon(self: Window, allocator: mem.Allocator, images: ?[]Image) Error!void { +pub inline fn setIcon(self: Window, allocator: mem.Allocator, images: ?[]Image) (mem.Allocator.Error || error{PlatformError})!void { internal_debug.assertInitialized(); if (images) |im| { const tmp = try allocator.alloc(c.GLFWimage, im.len); @@ -549,7 +576,8 @@ pub inline fn setIcon(self: Window, allocator: mem.Allocator, images: ?[]Image) c.glfwSetWindowIcon(self.handle, @intCast(c_int, im.len), &tmp[0]); } else c.glfwSetWindowIcon(self.handle, 0, null); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -572,13 +600,14 @@ pub const Pos = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_pos glfw.Window.setPos -pub inline fn getPos(self: Window) Error!Pos { +pub inline fn getPos(self: Window) error{PlatformError}!Pos { internal_debug.assertInitialized(); var x: c_int = 0; var y: c_int = 0; c.glfwGetWindowPos(self.handle, &x, &y); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return Pos{ .x = @intCast(usize, x), .y = @intCast(usize, y) }; @@ -604,11 +633,12 @@ pub inline fn getPos(self: Window) Error!Pos { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_pos, glfw.Window.getPos -pub inline fn setPos(self: Window, pos: Pos) Error!void { +pub inline fn setPos(self: Window, pos: Pos) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetWindowPos(self.handle, @intCast(c_int, pos.x), @intCast(c_int, pos.y)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -629,13 +659,14 @@ pub const Size = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_size, glfw.Window.setSize -pub inline fn getSize(self: Window) Error!Size { +pub inline fn getSize(self: Window) error{PlatformError}!Size { internal_debug.assertInitialized(); var width: c_int = 0; var height: c_int = 0; c.glfwGetWindowSize(self.handle, &width, &height); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return Size{ .width = @intCast(usize, width), .height = @intCast(usize, height) }; @@ -663,11 +694,12 @@ pub inline fn getSize(self: Window) Error!Size { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_size, glfw.Window.getSize, glfw.Window.SetMonitor -pub inline fn setSize(self: Window, size: Size) Error!void { +pub inline fn setSize(self: Window, size: Size) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetWindowSize(self.handle, @intCast(c_int, size.width), @intCast(c_int, size.height)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -693,7 +725,7 @@ pub inline fn setSize(self: Window, size: Size) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_sizelimits, glfw.Window.setAspectRatio -pub inline fn setSizeLimits(self: Window, min: Size, max: Size) Error!void { +pub inline fn setSizeLimits(self: Window, min: Size, max: Size) error{PlatformError}!void { internal_debug.assertInitialized(); if (min.width != glfw.dont_care and min.height != glfw.dont_care) { @@ -717,8 +749,9 @@ pub inline fn setSizeLimits(self: Window, min: Size, max: Size) Error!void { @intCast(c_int, max.height), ); getError() catch |err| return switch (err) { - Error.PlatformError => err, - Error.InvalidValue => unreachable, // we assert that 'min' and 'max' contain valid values, both absolutely and relative to each other, so this should be impossible + Error.NotInitialized => unreachable, + Error.InvalidValue => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -749,7 +782,7 @@ pub inline fn setSizeLimits(self: Window, min: Size, max: Size) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_sizelimits, glfw.Window.setSizeLimits -pub inline fn setAspectRatio(self: Window, numerator: usize, denominator: usize) Error!void { +pub inline fn setAspectRatio(self: Window, numerator: usize, denominator: usize) error{PlatformError}!void { internal_debug.assertInitialized(); std.debug.assert(numerator != 0); @@ -762,8 +795,9 @@ pub inline fn setAspectRatio(self: Window, numerator: usize, denominator: usize) c.glfwSetWindowAspectRatio(self.handle, @intCast(c_int, numerator), @intCast(c_int, denominator)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, Error.InvalidValue => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -778,13 +812,14 @@ pub inline fn setAspectRatio(self: Window, numerator: usize, denominator: usize) /// @thread_safety This function must only be called from the main thread. /// /// see also: window_fbsize, glfwWindow.setFramebufferSizeCallback -pub inline fn getFramebufferSize(self: Window) Error!Size { +pub inline fn getFramebufferSize(self: Window) error{PlatformError}!Size { internal_debug.assertInitialized(); var width: c_int = 0; var height: c_int = 0; c.glfwGetFramebufferSize(self.handle, &width, &height); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return Size{ .width = @intCast(usize, width), .height = @intCast(usize, height) }; @@ -811,7 +846,7 @@ pub const FrameSize = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_size -pub inline fn getFrameSize(self: Window) Error!FrameSize { +pub inline fn getFrameSize(self: Window) error{PlatformError}!FrameSize { internal_debug.assertInitialized(); var left: c_int = 0; var top: c_int = 0; @@ -819,7 +854,8 @@ pub inline fn getFrameSize(self: Window) Error!FrameSize { var bottom: c_int = 0; c.glfwGetWindowFrameSize(self.handle, &left, &top, &right, &bottom); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return FrameSize{ @@ -852,13 +888,14 @@ pub const ContentScale = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_scale, glfwSetWindowContentScaleCallback, glfwGetMonitorContentScale -pub inline fn getContentScale(self: Window) Error!ContentScale { +pub inline fn getContentScale(self: Window) error{PlatformError}!ContentScale { internal_debug.assertInitialized(); var x_scale: f32 = 0; var y_scale: f32 = 0; c.glfwGetWindowContentScale(self.handle, &x_scale, &y_scale); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return ContentScale{ .x_scale = x_scale, .y_scale = y_scale }; @@ -879,11 +916,12 @@ pub inline fn getContentScale(self: Window) Error!ContentScale { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_transparency, glfw.Window.setOpacity -pub inline fn getOpacity(self: Window) Error!f32 { +pub inline fn getOpacity(self: Window) error{PlatformError}!f32 { internal_debug.assertInitialized(); const opacity = c.glfwGetWindowOpacity(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return opacity; @@ -906,11 +944,12 @@ pub inline fn getOpacity(self: Window) Error!f32 { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_transparency, glfw.Window.getOpacity -pub inline fn setOpacity(self: Window, opacity: f32) Error!void { +pub inline fn setOpacity(self: Window, opacity: f32) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetWindowOpacity(self.handle, opacity); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -931,11 +970,12 @@ pub inline fn setOpacity(self: Window, opacity: f32) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_iconify, glfw.Window.restore, glfw.Window.maximize -pub inline fn iconify(self: Window) Error!void { +pub inline fn iconify(self: Window) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwIconifyWindow(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -953,11 +993,12 @@ pub inline fn iconify(self: Window) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_iconify, glfw.Window.iconify, glfw.Window.maximize -pub inline fn restore(self: Window) Error!void { +pub inline fn restore(self: Window) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwRestoreWindow(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -974,11 +1015,12 @@ pub inline fn restore(self: Window) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_iconify, glfw.Window.iconify, glfw.Window.restore -pub inline fn maximize(self: Window) Error!void { +pub inline fn maximize(self: Window) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwMaximizeWindow(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -997,11 +1039,12 @@ pub inline fn maximize(self: Window) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_hide, glfw.Window.hide -pub inline fn show(self: Window) Error!void { +pub inline fn show(self: Window) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwShowWindow(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1016,11 +1059,12 @@ pub inline fn show(self: Window) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_hide, glfw.Window.show -pub inline fn hide(self: Window) Error!void { +pub inline fn hide(self: Window) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwHideWindow(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1049,11 +1093,12 @@ pub inline fn hide(self: Window) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_focus, window_attention -pub inline fn focus(self: Window) Error!void { +pub inline fn focus(self: Window) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwFocusWindow(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1073,11 +1118,12 @@ pub inline fn focus(self: Window) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_attention -pub inline fn requestAttention(self: Window) Error!void { +pub inline fn requestAttention(self: Window) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwRequestWindowAttention(self.handle); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1103,13 +1149,14 @@ pub inline fn requestAttention(self: Window) Error!void { /// @thread_safety This function may be called from any thread. /// /// see also: buffer_swap, glfwSwapInterval -pub inline fn swapBuffers(self: Window) Error!void { +pub inline fn swapBuffers(self: Window) error{ NoWindowContext, PlatformError }!void { internal_debug.assertInitialized(); c.glfwSwapBuffers(self.handle); getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, Error.NoWindowContext, Error.PlatformError, - => err, + => @errSetCast(error{ NoWindowContext, PlatformError }, err), else => unreachable, }; } @@ -1128,7 +1175,10 @@ pub inline fn swapBuffers(self: Window) Error!void { pub inline fn getMonitor(self: Window) ?Monitor { internal_debug.assertInitialized(); const monitor = c.glfwGetWindowMonitor(self.handle); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; if (monitor) |m| return Monitor{ .handle = m }; return null; } @@ -1175,7 +1225,7 @@ pub inline fn getMonitor(self: Window) ?Monitor { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_monitor, window_full_screen, glfw.Window.getMonitor, glfw.Window.setSize -pub inline fn setMonitor(self: Window, monitor: ?Monitor, xpos: isize, ypos: isize, width: isize, height: isize, refresh_rate: isize) Error!void { +pub inline fn setMonitor(self: Window, monitor: ?Monitor, xpos: isize, ypos: isize, width: isize, height: isize, refresh_rate: isize) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetWindowMonitor( self.handle, @@ -1187,7 +1237,8 @@ pub inline fn setMonitor(self: Window, monitor: ?Monitor, xpos: isize, ypos: isi @intCast(c_int, refresh_rate), ); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1240,11 +1291,13 @@ pub const Attrib = enum(c_int) { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_attribs, glfw.Window.setAttrib -pub inline fn getAttrib(self: Window, attrib: Attrib) Error!isize { +pub inline fn getAttrib(self: Window, attrib: Attrib) error{PlatformError}!isize { internal_debug.assertInitialized(); const v = c.glfwGetWindowAttrib(self.handle, @enumToInt(attrib)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return v; @@ -1274,7 +1327,7 @@ pub inline fn getAttrib(self: Window, attrib: Attrib) Error!isize { /// /// see also: window_attribs, glfw.Window.getAttrib /// -pub inline fn setAttrib(self: Window, attrib: Attrib, value: bool) Error!void { +pub inline fn setAttrib(self: Window, attrib: Attrib, value: bool) error{PlatformError}!void { internal_debug.assertInitialized(); std.debug.assert(switch (attrib) { .decorated, @@ -1287,8 +1340,10 @@ pub inline fn setAttrib(self: Window, attrib: Attrib, value: bool) Error!void { }); c.glfwSetWindowAttrib(self.handle, @enumToInt(attrib), if (value) c.GLFW_TRUE else c.GLFW_FALSE); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, Error.InvalidValue => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1361,9 +1416,15 @@ pub inline fn setPosCallback(self: Window, callback: ?fn (window: Window, xpos: var internal = self.getInternal(); internal.setPosCallback = callback; _ = c.glfwSetWindowPosCallback(self.handle, if (callback != null) setPosCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } +// TODO: don't the calls to `from` in these `set*CallbackWrapper` functions cause a leak? +// is this what's being reported by valgrind in [#60](https://github.com/hexops/mach/issues/60)? + fn setSizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { internal_debug.assertInitialized(); const window = from(handle.?) catch unreachable; @@ -1389,7 +1450,10 @@ pub inline fn setSizeCallback(self: Window, callback: ?fn (window: Window, width var internal = self.getInternal(); internal.setSizeCallback = callback; _ = c.glfwSetWindowSizeCallback(self.handle, if (callback != null) setSizeCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setCloseCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { @@ -1425,7 +1489,10 @@ pub inline fn setCloseCallback(self: Window, callback: ?fn (window: Window) void var internal = self.getInternal(); internal.setCloseCallback = callback; _ = c.glfwSetWindowCloseCallback(self.handle, if (callback != null) setCloseCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setRefreshCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { @@ -1434,33 +1501,34 @@ fn setRefreshCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { internal.setRefreshCallback.?(window); } -// TODO: Something's off about this comment? -// /// Sets the refresh callback for the specified window. -// /// -// /// This function sets the refresh callback of the specified window, which is -// /// called when the content area of the window needs to be redrawn, for example -// /// if the window has been exposed after having been covered by another window. -// /// -// /// On compositing window systems such as Aero, Compiz, Aqua or Wayland, where -// /// the window contents are saved off-screen, this callback may be called only -// /// very infrequently or never at all. -// /// -// /// @param[in] window The window whose callback to set. -// /// @param[in] callback The new callback, or null to remove the currently set -// /// callback. -// /// -// /// @callback_param `window` the window whose content needs to be refreshed. -// /// -// /// @thread_safety This function must only be called from the main thread. -// /// -// /// see also: window_refresh -// GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun callback); +/// Sets the refresh callback for the specified window. +/// +/// This function sets the refresh callback of the specified window, which is +/// called when the content area of the window needs to be redrawn, for example +/// if the window has been exposed after having been covered by another window. +/// +/// On compositing window systems such as Aero, Compiz, Aqua or Wayland, where +/// the window contents are saved off-screen, this callback may be called only +/// very infrequently or never at all. +/// +/// @param[in] window The window whose callback to set. +/// @param[in] callback The new callback, or null to remove the currently set +/// callback. +/// +/// @callback_param `window` the window whose content needs to be refreshed. +/// +/// @thread_safety This function must only be called from the main thread. +/// +/// see also: window_refresh pub inline fn setRefreshCallback(self: Window, callback: ?fn (window: Window) void) void { internal_debug.assertInitialized(); var internal = self.getInternal(); internal.setRefreshCallback = callback; _ = c.glfwSetWindowRefreshCallback(self.handle, if (callback != null) setRefreshCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setFocusCallbackWrapper(handle: ?*c.GLFWwindow, focused: c_int) callconv(.C) void { @@ -1495,7 +1563,10 @@ pub inline fn setFocusCallback(self: Window, callback: ?fn (window: Window, focu var internal = self.getInternal(); internal.setFocusCallback = callback; _ = c.glfwSetWindowFocusCallback(self.handle, if (callback != null) setFocusCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setIconifyCallbackWrapper(handle: ?*c.GLFWwindow, iconified: c_int) callconv(.C) void { @@ -1528,7 +1599,10 @@ pub inline fn setIconifyCallback(self: Window, callback: ?fn (window: Window, ic var internal = self.getInternal(); internal.setIconifyCallback = callback; _ = c.glfwSetWindowIconifyCallback(self.handle, if (callback != null) setIconifyCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setMaximizeCallbackWrapper(handle: ?*c.GLFWwindow, maximized: c_int) callconv(.C) void { @@ -1559,7 +1633,10 @@ pub inline fn setMaximizeCallback(self: Window, callback: ?fn (window: Window, m var internal = self.getInternal(); internal.setMaximizeCallback = callback; _ = c.glfwSetWindowMaximizeCallback(self.handle, if (callback != null) setMaximizeCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setFramebufferSizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { @@ -1590,7 +1667,10 @@ pub inline fn setFramebufferSizeCallback(self: Window, callback: ?fn (window: Wi var internal = self.getInternal(); internal.setFramebufferSizeCallback = callback; _ = c.glfwSetFramebufferSizeCallback(self.handle, if (callback != null) setFramebufferSizeCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setContentScaleCallbackWrapper(handle: ?*c.GLFWwindow, xscale: f32, yscale: f32) callconv(.C) void { @@ -1621,7 +1701,10 @@ pub inline fn setContentScaleCallback(self: Window, callback: ?fn (window: Windo var internal = self.getInternal(); internal.setContentScaleCallback = callback; _ = c.glfwSetWindowContentScaleCallback(self.handle, if (callback != null) setContentScaleCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } pub const InputMode = enum(c_int) { @@ -1647,7 +1730,7 @@ pub const InputModeCursor = enum(c_int) { }; /// Sets the input mode of the cursor, whether it should behave normally, be hidden, or grabbed. -pub inline fn setInputModeCursor(self: Window, value: InputModeCursor) Error!void { +pub inline fn setInputModeCursor(self: Window, value: InputModeCursor) error{PlatformError}!void { return self.setInputMode(InputMode.cursor, value); } @@ -1661,7 +1744,7 @@ pub inline fn getInputModeCursor(self: Window) InputModeCursor { /// /// This is useful when you are only interested in whether keys have been pressed but not when or /// in which order. -pub inline fn setInputModeStickyKeys(self: Window, enabled: bool) Error!void { +pub inline fn setInputModeStickyKeys(self: Window, enabled: bool) error{PlatformError}!void { return self.setInputMode(InputMode.sticky_keys, enabled); } @@ -1676,7 +1759,7 @@ pub inline fn getInputModeStickyKeys(self: Window) bool { /// /// This is useful when you are only interested in whether buttons have been pressed but not when /// or in which order. -pub inline fn setInputModeStickyMouseButtons(self: Window, enabled: bool) Error!void { +pub inline fn setInputModeStickyMouseButtons(self: Window, enabled: bool) error{PlatformError}!void { return self.setInputMode(InputMode.sticky_mouse_buttons, enabled); } @@ -1688,7 +1771,7 @@ pub inline fn getInputModeStickyMouseButtons(self: Window) bool { /// Sets the input mode of locking key modifiers, if enabled callbacks that receive modifier bits /// will also have the glfw.mod.caps_lock bit set when the event was generated with Caps Lock on, /// and the glfw.mod.num_lock bit when Num Lock was on. -pub inline fn setInputModeLockKeyMods(self: Window, enabled: bool) Error!void { +pub inline fn setInputModeLockKeyMods(self: Window, enabled: bool) error{PlatformError}!void { return self.setInputMode(InputMode.lock_key_mods, enabled); } @@ -1703,7 +1786,7 @@ pub inline fn getInputModeLockKeyMods(self: Window) bool { /// /// If raw motion is not supported, attempting to set this will emit glfw.Error.PlatformError. Call /// glfw.rawMouseMotionSupported to check for support. -pub inline fn setInputModeRawMouseMotion(self: Window, enabled: bool) Error!void { +pub inline fn setInputModeRawMouseMotion(self: Window, enabled: bool) error{PlatformError}!void { return self.setInputMode(InputMode.raw_mouse_motion, enabled); } @@ -1736,8 +1819,11 @@ pub inline fn getInputMode(self: Window, mode: InputMode) isize { internal_debug.assertInitialized(); const value = c.glfwGetInputMode(self.handle, @enumToInt(mode)); - // Possible errors: 'GLFW_NOT_INITIALIZED' and 'GLFW_INVALID_ENUM'; we guarantee both to be unreachable - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.InvalidEnum => unreachable, + Error.NotInitialized => unreachable, + else => unreachable, + }; return @intCast(isize, value); } @@ -1761,7 +1847,7 @@ pub inline fn getInputMode(self: Window, mode: InputMode) isize { /// @thread_safety This function must only be called from the main thread. /// /// see also: glfw.Window.getInputMode -pub inline fn setInputMode(self: Window, mode: InputMode, value: anytype) Error!void { +pub inline fn setInputMode(self: Window, mode: InputMode, value: anytype) error{PlatformError}!void { internal_debug.assertInitialized(); const T = @TypeOf(value); std.debug.assert(switch (mode) { @@ -1783,7 +1869,9 @@ pub inline fn setInputMode(self: Window, mode: InputMode, value: anytype) Error! }; c.glfwSetInputMode(self.handle, @enumToInt(mode), int_value); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1817,7 +1905,11 @@ pub inline fn setInputMode(self: Window, mode: InputMode, value: anytype) Error! pub inline fn getKey(self: Window, key: Key) Action { internal_debug.assertInitialized(); const state = c.glfwGetKey(self.handle, @enumToInt(key)); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + else => unreachable, + }; return @intToEnum(Action, state); } @@ -1840,7 +1932,11 @@ pub inline fn getKey(self: Window, key: Key) Action { pub inline fn getMouseButton(self: Window, button: MouseButton) Action { internal_debug.assertInitialized(); const state = c.glfwGetMouseButton(self.handle, @enumToInt(button)); - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + else => unreachable, + }; return @intToEnum(Action, state); } @@ -1874,12 +1970,13 @@ pub const CursorPos = struct { /// @thread_safety This function must only be called from the main thread. /// /// see also: cursor_pos, glfw.Window.setCursorPos -pub inline fn getCursorPos(self: Window) Error!CursorPos { +pub inline fn getCursorPos(self: Window) error{PlatformError}!CursorPos { internal_debug.assertInitialized(); var pos: CursorPos = undefined; c.glfwGetCursorPos(self.handle, &pos.xpos, &pos.ypos); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return pos; @@ -1910,11 +2007,12 @@ pub inline fn getCursorPos(self: Window) Error!CursorPos { /// @thread_safety This function must only be called from the main thread. /// /// see also: cursor_pos, glfw.Window.getCursorPos -pub inline fn setCursorPos(self: Window, xpos: f64, ypos: f64) Error!void { +pub inline fn setCursorPos(self: Window, xpos: f64, ypos: f64) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetCursorPos(self.handle, xpos, ypos); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1934,11 +2032,12 @@ pub inline fn setCursorPos(self: Window, xpos: f64, ypos: f64) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: cursor_object -pub inline fn setCursor(self: Window, cursor: Cursor) Error!void { +pub inline fn setCursor(self: Window, cursor: Cursor) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetCursor(self.handle, cursor.ptr); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -1988,7 +2087,10 @@ pub inline fn setKeyCallback(self: Window, callback: ?fn (window: Window, key: K var internal = self.getInternal(); internal.setKeyCallback = callback; _ = c.glfwSetKeyCallback(self.handle, if (callback != null) setKeyCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setCharCallbackWrapper(handle: ?*c.GLFWwindow, codepoint: c_uint) callconv(.C) void { @@ -2026,7 +2128,10 @@ pub inline fn setCharCallback(self: Window, callback: ?fn (window: Window, codep var internal = self.getInternal(); internal.setCharCallback = callback; _ = c.glfwSetCharCallback(self.handle, if (callback != null) setCharCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setMouseButtonCallbackWrapper(handle: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) callconv(.C) void { @@ -2062,7 +2167,10 @@ pub inline fn setMouseButtonCallback(self: Window, callback: ?fn (window: Window var internal = self.getInternal(); internal.setMouseButtonCallback = callback; _ = c.glfwSetMouseButtonCallback(self.handle, if (callback != null) setMouseButtonCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setCursorPosCallbackWrapper(handle: ?*c.GLFWwindow, xpos: f64, ypos: f64) callconv(.C) void { @@ -2093,7 +2201,10 @@ pub inline fn setCursorPosCallback(self: Window, callback: ?fn (window: Window, var internal = self.getInternal(); internal.setCursorPosCallback = callback; _ = c.glfwSetCursorPosCallback(self.handle, if (callback != null) setCursorPosCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setCursorEnterCallbackWrapper(handle: ?*c.GLFWwindow, entered: c_int) callconv(.C) void { @@ -2121,7 +2232,10 @@ pub inline fn setCursorEnterCallback(self: Window, callback: ?fn (window: Window var internal = self.getInternal(); internal.setCursorEnterCallback = callback; _ = c.glfwSetCursorEnterCallback(self.handle, if (callback != null) setCursorEnterCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setScrollCallbackWrapper(handle: ?*c.GLFWwindow, xoffset: f64, yoffset: f64) callconv(.C) void { @@ -2153,7 +2267,10 @@ pub inline fn setScrollCallback(self: Window, callback: ?fn (window: Window, xof var internal = self.getInternal(); internal.setScrollCallback = callback; _ = c.glfwSetScrollCallback(self.handle, if (callback != null) setScrollCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } fn setDropCallbackWrapper(handle: ?*c.GLFWwindow, path_count: c_int, paths: [*c][*c]const u8) callconv(.C) void { @@ -2192,7 +2309,10 @@ pub inline fn setDropCallback(self: Window, callback: ?fn (window: Window, paths var internal = self.getInternal(); internal.setDropCallback = callback; _ = c.glfwSetDropCallback(self.handle, if (callback != null) setDropCallbackWrapper else null); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } /// For testing purposes only; see glfw.Window.Hints and glfw.Window.create for the public API. @@ -2255,7 +2375,11 @@ inline fn hint(h: Hint, value: anytype) void { @compileError("expected a int, bool, enum, array, or pointer, got " ++ @typeName(value_type)); }, } - getError() catch unreachable; + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + else => unreachable, + }; } test "defaultHints" { diff --git a/glfw/src/clipboard.zig b/glfw/src/clipboard.zig index 336c6b22..3c919484 100644 --- a/glfw/src/clipboard.zig +++ b/glfw/src/clipboard.zig @@ -19,11 +19,12 @@ const internal_debug = @import("internal_debug.zig"); /// @thread_safety This function must only be called from the main thread. /// /// see also: clipboard, glfwGetClipboardString -pub inline fn setClipboardString(value: [*:0]const u8) Error!void { +pub inline fn setClipboardString(value: [*:0]const u8) error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwSetClipboardString(null, value); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -45,13 +46,14 @@ pub inline fn setClipboardString(value: [*:0]const u8) Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: clipboard, glfwSetClipboardString -pub inline fn getClipboardString() Error![:0]const u8 { +pub inline fn getClipboardString() error{ FormatUnavailable, PlatformError }![:0]const u8 { internal_debug.assertInitialized(); const value = c.glfwGetClipboardString(null); getError() catch |err| return switch (err) { - Error.PlatformError, + Error.NotInitialized => unreachable, Error.FormatUnavailable, - => err, + Error.PlatformError, + => @errSetCast(error{ FormatUnavailable, PlatformError }, err), else => unreachable, }; return std.mem.span(value); diff --git a/glfw/src/errors.zig b/glfw/src/errors.zig index 61c85299..72750dd2 100644 --- a/glfw/src/errors.zig +++ b/glfw/src/errors.zig @@ -4,6 +4,12 @@ const c = @import("c.zig").c; /// Errors that GLFW can produce. pub const Error = error{ + /// GLFW has not been initialized. + /// + /// This occurs if a GLFW function was called that must not be called unless the library is + /// initialized. + NotInitialized, + /// No context is current for this thread. /// /// This occurs if a GLFW function was called that needs and operates on the current OpenGL or @@ -11,6 +17,12 @@ pub const Error = error{ /// glfw.SwapInterval. NoCurrentContext, + /// One of the arguments to the function was an invalid enum value. + /// + /// One of the arguments to the function was an invalid enum value, for example requesting + /// glfw.red_bits with glfw.getWindowAttrib. + InvalidEnum, + /// One of the arguments to the function was an invalid value. /// /// One of the arguments to the function was an invalid value, for example requesting a @@ -78,9 +90,9 @@ pub const Error = error{ fn convertError(e: c_int) Error!void { return switch (e) { c.GLFW_NO_ERROR => {}, - c.GLFW_NOT_INITIALIZED => unreachable, + c.GLFW_NOT_INITIALIZED => Error.NotInitialized, c.GLFW_NO_CURRENT_CONTEXT => Error.NoCurrentContext, - c.GLFW_INVALID_ENUM => unreachable, + c.GLFW_INVALID_ENUM => Error.InvalidEnum, c.GLFW_INVALID_VALUE => Error.InvalidValue, c.GLFW_OUT_OF_MEMORY => Error.OutOfMemory, c.GLFW_API_UNAVAILABLE => Error.APIUnavailable, diff --git a/glfw/src/key.zig b/glfw/src/key.zig index 572cbf87..59ec36ef 100644 --- a/glfw/src/key.zig +++ b/glfw/src/key.zig @@ -214,11 +214,12 @@ pub const Key = enum(c_int) { /// @thread_safety This function must only be called from the main thread. /// /// see also: input_key_name - pub inline fn getName(self: Key, scancode: isize) Error!?[:0]const u8 { + pub inline fn getName(self: Key, scancode: isize) error{PlatformError}!?[:0]const u8 { internal_debug.assertInitialized(); const name_opt = cc.glfwGetKeyName(@enumToInt(self), @intCast(c_int, scancode)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return if (name_opt) |name| @@ -239,11 +240,13 @@ pub const Key = enum(c_int) { /// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError. /// /// @thread_safety This function may be called from any thread. - pub inline fn getScancode(self: Key) Error!isize { + pub inline fn getScancode(self: Key) error{PlatformError}!isize { internal_debug.assertInitialized(); const scancode = cc.glfwGetKeyScancode(@enumToInt(self)); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidEnum => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; return scancode; diff --git a/glfw/src/main.zig b/glfw/src/main.zig index 2fd92f6c..0a30efce 100644 --- a/glfw/src/main.zig +++ b/glfw/src/main.zig @@ -57,10 +57,13 @@ const internal_debug = @import("internal_debug.zig"); /// Unicode text input. /// /// @thread_safety This function must only be called from the main thread. -pub inline fn init(hints: InitHints) Error!void { +pub inline fn init(hints: InitHints) error{PlatformError}!void { internal_debug.toggleInitialized(); internal_debug.assertInitialized(); - errdefer internal_debug.toggleInitialized(); + errdefer { + internal_debug.assertInitialized(); + internal_debug.toggleInitialized(); + } inline for (comptime std.meta.fieldNames(InitHints)) |field_name| { const init_hint = @field(InitHint, field_name); @@ -70,7 +73,7 @@ pub inline fn init(hints: InitHints) Error!void { _ = c.glfwInit(); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -89,6 +92,7 @@ pub inline fn init(hints: InitHints) Error!void { /// /// Possible errors include glfw.Error.PlatformError. /// +// TODO: Should this remark be removed? Or should we allow this function to be called before init? /// remark: This function may be called before glfw.init. /// /// warning: The contexts of any remaining windows must not be current on any other thread when @@ -101,6 +105,10 @@ pub inline fn terminate() void { internal_debug.assertInitialized(); internal_debug.toggleInitialized(); c.glfwTerminate(); + getError() catch |err| return switch (err) { + Error.PlatformError => std.log.err("mach/glfw: Failed to terminate GLFW: {}", .{err}), + else => unreachable, + }; } /// Initialization hints for passing into glfw.init @@ -177,7 +185,8 @@ fn initHint(hint: InitHint, value: anytype) void { else => @compileError("expected a int or bool, got " ++ @typeName(@TypeOf(value))), } getError() catch |err| return switch (err) { - Error.InvalidValue => unreachable, // we assert that 'value' is valid if it is an integer, so this should be impossible + Error.InvalidEnum => unreachable, + Error.InvalidValue => unreachable, else => unreachable, }; } @@ -201,7 +210,11 @@ fn initHint(hint: InitHint, value: anytype) void { /// /// @thread_safety This function may be called from any thread. pub inline fn getVersionString() [:0]const u8 { - return std.mem.span(c.glfwGetVersionString()); + const result = std.mem.span(c.glfwGetVersionString()); + getError() catch |err| switch (err) { + else => unreachable, + }; + return result; } /// Processes all pending events. @@ -229,11 +242,12 @@ pub inline fn getVersionString() [:0]const u8 { /// @thread_safety This function must only be called from the main thread. /// /// see also: events, glfw.waitEvents, glfw.waitEventsTimeout -pub inline fn pollEvents() Error!void { +pub inline fn pollEvents() error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwPollEvents(); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -268,11 +282,12 @@ pub inline fn pollEvents() Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: events, glfw.pollEvents, glfw.waitEventsTimeout -pub inline fn waitEvents() Error!void { +pub inline fn waitEvents() error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwWaitEvents(); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -311,15 +326,16 @@ pub inline fn waitEvents() Error!void { /// @thread_safety This function must only be called from the main thread. /// /// see also: events, glfw.pollEvents, glfw.waitEvents -pub inline fn waitEventsTimeout(timeout: f64) Error!void { +pub inline fn waitEventsTimeout(timeout: f64) error{PlatformError}!void { internal_debug.assertInitialized(); std.debug.assert(!std.math.isNan(timeout)); std.debug.assert(timeout >= 0); std.debug.assert(timeout <= std.math.f64_max); c.glfwWaitEventsTimeout(timeout); getError() catch |err| return switch (err) { - Error.InvalidValue => unreachable, // we assert that 'timeout' is a valid value, so this should be impossible - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.InvalidValue => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -334,11 +350,12 @@ pub inline fn waitEventsTimeout(timeout: f64) Error!void { /// @thread_safety This function may be called from any thread. /// /// see also: events, glfw.waitEvents, glfw.waitEventsTimeout -pub inline fn postEmptyEvent() Error!void { +pub inline fn postEmptyEvent() error{PlatformError}!void { internal_debug.assertInitialized(); c.glfwPostEmptyEvent(); getError() catch |err| return switch (err) { - Error.PlatformError => err, + Error.NotInitialized => unreachable, + Error.PlatformError => @errSetCast(error{PlatformError}, err), else => unreachable, }; } @@ -363,7 +380,10 @@ pub inline fn postEmptyEvent() Error!void { pub inline fn rawMouseMotionSupported() bool { internal_debug.assertInitialized(); const supported = c.glfwRawMouseMotionSupported(); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; return supported == c.GLFW_TRUE; } diff --git a/glfw/src/opengl.zig b/glfw/src/opengl.zig index 6f5ce3d3..cf996b09 100644 --- a/glfw/src/opengl.zig +++ b/glfw/src/opengl.zig @@ -31,13 +31,14 @@ const internal_debug = @import("internal_debug.zig"); /// @thread_safety This function may be called from any thread. /// /// see also: context_current, glfwGetCurrentContext -pub inline fn makeContextCurrent(window: ?Window) Error!void { +pub inline fn makeContextCurrent(window: ?Window) error{ NoWindowContext, PlatformError }!void { internal_debug.assertInitialized(); if (window) |w| c.glfwMakeContextCurrent(w.handle) else c.glfwMakeContextCurrent(null); getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, Error.NoWindowContext, Error.PlatformError, - => err, + => @errSetCast(error{ NoWindowContext, PlatformError }, err), else => unreachable, }; } @@ -57,7 +58,10 @@ pub inline fn makeContextCurrent(window: ?Window) Error!void { pub inline fn getCurrentContext() std.mem.Allocator.Error!?Window { internal_debug.assertInitialized(); const handle = c.glfwGetCurrentContext(); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; if (handle) |h| return try Window.from(h); return null; } @@ -95,13 +99,14 @@ pub inline fn getCurrentContext() std.mem.Allocator.Error!?Window { /// @thread_safety This function may be called from any thread. /// /// see also: buffer_swap, glfwSwapBuffers -pub inline fn swapInterval(interval: isize) Error!void { +pub inline fn swapInterval(interval: isize) error{ NoCurrentContext, PlatformError }!void { internal_debug.assertInitialized(); c.glfwSwapInterval(@intCast(c_int, interval)); getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, Error.NoCurrentContext, Error.PlatformError, - => err, + => @errSetCast(error{ NoCurrentContext, PlatformError }, err), else => unreachable, }; } @@ -131,7 +136,7 @@ pub inline fn swapInterval(interval: isize) Error!void { /// @thread_safety This function may be called from any thread. /// /// see also: context_glext, glfw.getProcAddress -pub inline fn extensionSupported(extension: [:0]const u8) Error!bool { +pub inline fn extensionSupported(extension: [:0]const u8) error{ NoCurrentContext, PlatformError }!bool { internal_debug.assertInitialized(); std.debug.assert(extension.len != 0); @@ -139,8 +144,11 @@ pub inline fn extensionSupported(extension: [:0]const u8) Error!bool { const supported = c.glfwExtensionSupported(extension); getError() catch |err| return switch (err) { - Error.NoCurrentContext => err, - Error.InvalidValue => unreachable, // we assert that 'extension' is a minimally valid value, so this should be impossible + Error.NoCurrentContext, + Error.PlatformError, + => @errSetCast(error{ NoCurrentContext, PlatformError }, err), + Error.NotInitialized => unreachable, + Error.InvalidValue => unreachable, else => unreachable, }; return supported == c.GLFW_TRUE; diff --git a/glfw/src/time.zig b/glfw/src/time.zig index e1435e20..b4e46d0e 100644 --- a/glfw/src/time.zig +++ b/glfw/src/time.zig @@ -30,7 +30,10 @@ const internal_debug = @import("internal_debug.zig"); pub inline fn getTime() f64 { internal_debug.assertInitialized(); const time = c.glfwGetTime(); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; return time; } @@ -66,7 +69,8 @@ pub inline fn setTime(time: f64) void { c.glfwSetTime(time); getError() catch |err| return switch (err) { - Error.InvalidValue => unreachable, // we assert that 'time' is a valid value, so this should be impossible + Error.NotInitialized => unreachable, + Error.InvalidValue => unreachable, else => unreachable, }; } @@ -84,7 +88,10 @@ pub inline fn setTime(time: f64) void { pub inline fn getTimerValue() u64 { internal_debug.assertInitialized(); const value = c.glfwGetTimerValue(); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; return value; } @@ -100,7 +107,10 @@ pub inline fn getTimerValue() u64 { pub inline fn getTimerFrequency() u64 { internal_debug.assertInitialized(); const frequency = c.glfwGetTimerFrequency(); - getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; return frequency; } diff --git a/glfw/src/vulkan.zig b/glfw/src/vulkan.zig index e29a4efa..f27e69f4 100644 --- a/glfw/src/vulkan.zig +++ b/glfw/src/vulkan.zig @@ -60,12 +60,13 @@ pub inline fn vulkanSupported() bool { /// @thread_safety This function may be called from any thread. /// /// see also: vulkan_ext, glfwCreateWindowSurface -pub inline fn getRequiredInstanceExtensions() Error![][*:0]const u8 { +pub inline fn getRequiredInstanceExtensions() error{APIUnavailable}![][*:0]const u8 { internal_debug.assertInitialized(); var count: u32 = 0; const extensions = c.glfwGetRequiredInstanceExtensions(&count); getError() catch |err| return switch (err) { - Error.APIUnavailable => err, + Error.NotInitialized => unreachable, + Error.APIUnavailable => @errSetCast(error{APIUnavailable}, err), else => unreachable, }; return @ptrCast([*][*:0]const u8, extensions)[0..count]; @@ -142,7 +143,11 @@ pub fn getInstanceProcAddress(vk_instance: ?*opaque {}, proc_name: [*:0]const u8 /// Vulkan objects, see the Vulkan specification. /// /// see also: vulkan_present -pub inline fn getPhysicalDevicePresentationSupport(vk_instance: *opaque {}, vk_physical_device: *opaque {}, queue_family: u32) Error!bool { +pub inline fn getPhysicalDevicePresentationSupport( + vk_instance: *opaque {}, + vk_physical_device: *opaque {}, + queue_family: u32, +) error{ APIUnavailable, PlatformError }!bool { internal_debug.assertInitialized(); const v = c.glfwGetPhysicalDevicePresentationSupport( @ptrCast(c.VkInstance, vk_instance), @@ -150,9 +155,10 @@ pub inline fn getPhysicalDevicePresentationSupport(vk_instance: *opaque {}, vk_p queue_family, ); getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, Error.APIUnavailable, Error.PlatformError, - => err, + => @errSetCast(error{ APIUnavailable, PlatformError }, err), else => unreachable, }; return v == c.GLFW_TRUE; @@ -203,7 +209,7 @@ pub inline fn getPhysicalDevicePresentationSupport(vk_instance: *opaque {}, vk_p /// Vulkan objects, see the Vulkan specification. /// /// see also: vulkan_surface, glfw.getRequiredInstanceExtensions -pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_allocation_callbacks: anytype, vk_surface_khr: anytype) Error!i32 { +pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_allocation_callbacks: anytype, vk_surface_khr: anytype) error{ APIUnavailable, PlatformError }!i32 { internal_debug.assertInitialized(); // zig-vulkan uses enums to represent opaque pointers: // pub const Instance = enum(usize) { null_handle = 0, _ }; @@ -219,6 +225,7 @@ pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_alloc @ptrCast(*c.VkSurfaceKHR, @alignCast(@alignOf(c.VkSurfaceKHR), vk_surface_khr)), ); getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, Error.InvalidValue => @panic("Attempted to use window with client api to create vulkan surface."), Error.APIUnavailable, Error.PlatformError,