const std = @import("std"); /// /// Errors that may occur during checked integer arithmetic operations. /// pub const CheckedArithmeticError = error { IntOverflow, }; /// /// Returns the float type described by `float`. /// pub fn Float(comptime float: std.builtin.Type.Float) type { return @Type(.{.Float = float}); } /// /// Returns the integer type described by `int`. /// pub fn Int(comptime int: std.builtin.Type.Int) type { return @Type(.{.Int = int}); } /// /// Two-dimensional vector type. /// pub const Vector2 = extern struct { x: f32, y: f32, /// /// A [Vector2] with a value of `0` assigned to all of the components. /// pub const zero = Vector2{.x = 0, .y = 0}; }; /// /// Attempts to perform a checked addition between `a` and `b`, returning the result or [CheckedArithmeticError] if the /// operation tried to invoke safety-checked behavior. /// /// `checked_add` can be seen as an alternative to the language-native addition operator (+) that exposes the safety- /// checked behavior in the form of an error type that may be caught or tried on. /// pub fn checked_add(a: anytype, b: anytype) CheckedArithmeticError!@TypeOf(a + b) { const result = @addWithOverflow(a, b); if (result.@"1" != 0) { return error.IntOverflow; } return result.@"0"; } /// /// Attempts to perform a checked integer cast to the type expressed by `int` on `value`, returning the result or /// [CheckedArithmeticError] if the operation tried to invoke safety-checked behavior. /// /// `checked_cast` can be seen as an alternative to the language-native `@intCast` builtin that exposes the safety- /// checked behavior in the form of an error type that may be caught or tried on. /// pub fn checked_cast(comptime int: std.builtin.Type.Int, value: anytype) CheckedArithmeticError!Int(int) { if ((value < min_int(int)) or (value > max_int(int))) { return error.IntOverflow; } return @intCast(Int(int), value); } /// /// Attempts to perform a checked multiplication between `a` and `b`, returning the result or [CheckedArithmeticError] /// if the operation tried to invoke safety-checked behavior. /// /// `checked_mul` can be seen as an alternative to the language-native multiplication operator (*) that exposes the /// safety-checked behavior in the form of an error type that may be caught or tried on. /// pub fn checked_mul(a: anytype, b: anytype) CheckedArithmeticError!@TypeOf(a * b) { const result = @mulWithOverflow(a, b); if (result.@"1" != 0) { return error.IntOverflow; } return result.@"0"; } /// /// Attempts to perform a checked subtraction between `a` and `b`, returning the result or [CheckedArithmeticError] if /// the operation tried to invoke safety-checked behavior. /// /// `checked_sub` can be seen as an alternative to the language-native subtraction operator (-) that exposes the safety- /// checked behavior in the form of an error type that may be caught or tried on. /// pub fn checked_sub(a: anytype, b: anytype) CheckedArithmeticError!@TypeOf(a - b) { const result = @subWithOverflow(a, b); if (result.@"1" != 0) { return error.IntOverflow; } return result.@"0"; } /// /// Returns `value` clamped between the inclusive bounds of `lower` and `upper`. /// pub fn clamp(value: anytype, lower: anytype, upper: anytype) @TypeOf(value, lower, upper) { return max(lower, min(upper, value)); } /// /// Returns `true` if `value` is clamped within the inclusive bounds of `lower` and `upper`. /// pub fn is_clamped(value: anytype, lower: anytype, upper: anytype) bool { return (value >= lower) and (value <= upper); } /// /// Returns the maximum value between `a` and `b`. /// pub fn max(a: anytype, b: anytype) @TypeOf(a, b) { return @max(a, b); } /// /// Returns the maximum value that the integer described by `int` may express. /// pub fn max_int(comptime int: std.builtin.Type.Int) comptime_int { const bit_count = int.bits; if (bit_count == 0) return 0; return (1 << (bit_count - @boolToInt(int.signedness == .signed))) - 1; } /// /// Returns the minimum value between `a` and `b`. /// pub fn min(a: anytype, b: anytype) @TypeOf(a, b) { return @min(a, b); } /// /// Returns the minimum value that the integer described by `int` may express. /// pub fn min_int(comptime int: std.builtin.Type.Int) comptime_int { if (int.signedness == .unsigned) return 0; const bit_count = int.bits; if (bit_count == 0) return 0; return -(1 << (bit_count - 1)); } /// /// Returns `value` wrapped around the inclusive bounds of `lower` and `upper`. /// pub fn wrap(value: anytype, lower: anytype, upper: anytype) @TypeOf(value, lower, upper) { const range = upper - lower; return if (range == 0) lower else lower + @mod((@mod((value - lower), range) + range), range); }