Skip to content

Commit

Permalink
handle std.builtin.Type name changes (ziglang/zig#21225)
Browse files Browse the repository at this point in the history
rather tedious to have to support both naming styles
  • Loading branch information
scheibo committed Aug 29, 2024
1 parent 2f7925f commit 5911940
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 127 deletions.
9 changes: 6 additions & 3 deletions src/lib/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const assert = std.debug.assert;

const ERROR: u8 = 0b1100;

const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;

export const PKMN_OPTIONS: extern struct {
showdown: bool,
log: bool,
Expand All @@ -24,7 +26,7 @@ export const PKMN_MAX_LOGS = pkmn.MAX_LOGS;
export const PKMN_LOGS_SIZE = pkmn.LOGS_SIZE;

export fn pkmn_choice_init(choice: u8, data: u8) u8 {
assert(choice <= @typeInfo(pkmn.Choice.Type).Enum.fields.len);
assert(choice <= @field(@typeInfo(pkmn.Choice.Type), @tagName(Enum)).fields.len);
assert(data <= 6);
return @bitCast(pkmn.Choice{ .type = @enumFromInt(choice), .data = @intCast(data) });
}
Expand Down Expand Up @@ -176,8 +178,9 @@ export fn pkmn_gen1_battle_choices(
out: [*]u8,
len: usize,
) u8 {
assert(player <= @typeInfo(pkmn.Player).Enum.fields.len);
assert(request <= @typeInfo(pkmn.Choice.Type).Enum.fields.len);
assert(player <= @field(@typeInfo(pkmn.Player), @tagName(Enum)).fields.len);
assert(request <= @field(@typeInfo(pkmn.Choice.Type), @tagName(Enum)).fields.len);

assert(!pkmn.options.showdown or len > 0);
return battle.choices(@enumFromInt(player), @enumFromInt(request), @ptrCast(out[0..len]));
}
17 changes: 12 additions & 5 deletions src/lib/common/array.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@ const std = @import("std");
const expectEqual = std.testing.expectEqual;
const assert = std.debug.assert;

const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;

/// Helpers for working with bit-packed arrays of non-powers-of-2 types.
/// NOTE: ziglang/zig#12547
pub fn Array(comptime n: comptime_int, comptime U: type) type {
return struct {
const size = @bitSizeOf(U);
pub const T = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = size * n } });
const options = .{ .signedness = .unsigned, .bits = size * n };
pub const T = @Type(if (@hasField(std.builtin.Type, "int"))
.{ .int = options }
else
.{ .Int = options });

/// Returns the value stored at index `i` in the array `a`.
pub fn get(a: T, i: usize) U {
Expand All @@ -17,8 +24,8 @@ pub fn Array(comptime n: comptime_int, comptime U: type) type {
const mask: T = (1 << size) - 1;
const result = (a >> @intCast(shift)) & mask;
return switch (@typeInfo(U)) {
.Enum => @enumFromInt(result),
.Int => @intCast(result),
Enum => @enumFromInt(result),
Int => @intCast(result),
else => unreachable,
};
}
Expand All @@ -27,8 +34,8 @@ pub fn Array(comptime n: comptime_int, comptime U: type) type {
pub fn set(a: T, i: usize, val: U) T {
assert(i < n);
const v: T = switch (@typeInfo(U)) {
.Enum => @intFromEnum(val),
.Int => @intCast(val),
Enum => @intFromEnum(val),
Int => @intCast(val),
else => unreachable,
};
const shift = i * size;
Expand Down
6 changes: 4 additions & 2 deletions src/lib/common/js.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const std = @import("std");

const assert = std.debug.assert;

const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;

const c = @cImport({
@cDefine("NAPI_VERSION", "8");
@cInclude("node_api.h");
Expand Down Expand Up @@ -35,7 +37,7 @@ pub const Number = struct {
const T = @TypeOf(value);
var result: c.napi_value = undefined;
assert(c.napi_ok == switch (@typeInfo(T)) {
.Int => |info| switch (info.bits) {
Int => |info| switch (info.bits) {
0...32 => switch (info.signedness) {
.signed => c.napi_create_int32(env, @as(i32, value), &result),
.unsigned => c.napi_create_uint32(env, @as(u32, value), &result),
Expand All @@ -50,7 +52,7 @@ pub const Number = struct {

pub fn get(env: c.napi_env, value: c.napi_value, comptime T: type) T {
switch (@typeInfo(T)) {
.Int => |info| switch (info.bits) {
Int => |info| switch (info.bits) {
0...32 => switch (info.signedness) {
.signed => {
var result: i32 = undefined;
Expand Down
22 changes: 13 additions & 9 deletions src/lib/common/optional.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ const std = @import("std");
const expect = std.testing.expect;
const assert = std.debug.assert;

const Bool = if (@hasField(std.builtin.Type, "bool")) .bool else .Bool;

// TODO: ziglang/zig#104
pub fn Optional(comptime T: type) type {
const fields = std.meta.fields(switch (@typeInfo(T)) {
.Bool => enum { false, true },
Bool => enum { false, true },
else => T,
});

Expand All @@ -23,14 +25,16 @@ pub fn Optional(comptime T: type) type {
};
}

return @Type(.{
.Enum = .{
.tag_type = std.math.IntFittingRange(0, fields.len),
.fields = &enumFields,
.decls = &decls,
.is_exhaustive = true,
},
});
const options = .{
.tag_type = std.math.IntFittingRange(0, fields.len),
.fields = &enumFields,
.decls = &decls,
.is_exhaustive = true,
};
return @Type(if (@hasField(std.builtin.Type, "enum"))
.{ .@"enum" = options }
else
.{ .Enum = options });
}

test Optional {
Expand Down
4 changes: 3 additions & 1 deletion src/lib/common/protocol.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const Endian = std.builtin.Endian;
const big = if (@hasField(Endian, "big")) Endian.big else Endian.Big;
const little = if (@hasField(Endian, "little")) Endian.little else Endian.Little;

const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;

pub const ArgType = enum(u8) {
None,

Expand Down Expand Up @@ -843,7 +845,7 @@ pub const ByteStream = struct {

pub fn writeInt(self: Writer, comptime T: type, v: T, end: std.builtin.Endian) Error!void {
// TODO: rework this to write directly to the buffer?
var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined;
var bytes: [@divExact(@field(@typeInfo(T), @tagName(Int)).bits, 8)]u8 = undefined;
std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(v)), &bytes, v, end);
return self.writeAll(&bytes);
}
Expand Down
33 changes: 20 additions & 13 deletions src/lib/common/rational.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError;

const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
const Float = if (@hasField(std.builtin.Type, "float")) .float else .Float;
const ComptimeInt =
if (@hasField(std.builtin.Type, "comptime_int")) .comptime_int else .ComptimeInt;
const ComptimeFloat =
if (@hasField(std.builtin.Type, "comptime_float")) .comptime_float else .ComptimeFloat;

/// Specialization of a rational number used by the engine to compute probabilties.
/// For performance reasons the rational is only reduced lazily and thus `reduce` must be
/// invoked explicitly before reading.
Expand All @@ -22,15 +29,15 @@ pub fn Rational(comptime T: type) type {
// start reducing when we get sufficiently close to the limit of the mantissa (in our domain
// we expect updates to involve numbers < 2**10, so we should be safe not reducing before we
// are 2**10 away from "overflowing" the mantissa)
const REDUCE = if (@typeInfo(T) == .Float)
const REDUCE = if (@typeInfo(T) == Float)
std.math.pow(T, 2, std.math.floatMantissaBits(T) - 10)
else
0;

/// Possible error returned by operations on the Rational.
pub const Error = switch (@typeInfo(T)) {
.Int => error{Overflow},
.Float => error{},
Int => error{Overflow},
Float => error{},
else => unreachable,
};

Expand All @@ -50,12 +57,12 @@ pub fn Rational(comptime T: type) type {
// If our parameters are not fully reduced they may prematurely
// cause overflow/loss of precision after the multiplication below
assert(switch (@typeInfo(@TypeOf(p, q))) {
.ComptimeInt, .ComptimeFloat => comptime gcd(p, q),
ComptimeInt, ComptimeFloat => comptime gcd(p, q),
else => 1,
} == 1);

switch (@typeInfo(T)) {
.Int => {
Int => {
// Greedily attempt to multiply and if it fails, reduce and try again
r.multiplication(p, q) catch |err| switch (err) {
error.Overflow => {
Expand All @@ -65,16 +72,16 @@ pub fn Rational(comptime T: type) type {
else => unreachable,
};
},
.Float => {
Float => {
// Reduce in situations where we're likely to start losing precision
if (r.q > REDUCE or r.p > REDUCE) r.reduce();

r.p *= switch (@typeInfo(@TypeOf(p))) {
.Float, .ComptimeFloat => p,
Float, ComptimeFloat => p,
else => @floatFromInt(p),
};
r.q *= switch (@typeInfo(@TypeOf(q))) {
.Float, .ComptimeFloat => q,
Float, ComptimeFloat => q,
else => @floatFromInt(q),
};

Expand All @@ -89,7 +96,7 @@ pub fn Rational(comptime T: type) type {
/// Add two rationals using the identity (a/b) + (c/d) = (ad+bc)/(bd).
pub fn add(r: *Self, s: *Self) Error!void {
switch (@typeInfo(T)) {
.Int => {
Int => {
if (r.q == s.q) {
r.p = std.math.add(T, r.p, s.p) catch |err| switch (err) {
error.Overflow => val: {
Expand All @@ -110,7 +117,7 @@ pub fn Rational(comptime T: type) type {
};
}
},
.Float => {
Float => {
if (r.q == s.q) {
if (r.p > REDUCE) r.reduce();
if (s.p > REDUCE) s.reduce();
Expand All @@ -135,7 +142,7 @@ pub fn Rational(comptime T: type) type {
/// Multiplies two rationals.
pub fn mul(r: *Self, s: *Self) Error!void {
switch (@typeInfo(T)) {
.Int => {
Int => {
r.multiplication(s.p, s.q) catch |err| switch (err) {
error.Overflow => {
r.reduce();
Expand All @@ -145,7 +152,7 @@ pub fn Rational(comptime T: type) type {
else => unreachable,
};
},
.Float => {
Float => {
if (r.q > REDUCE or r.p > REDUCE) r.reduce();
if (s.q > REDUCE or s.p > REDUCE) s.reduce();

Expand Down Expand Up @@ -212,7 +219,7 @@ fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
};

switch (@typeInfo(T)) {
.Int => {
Int => {
// std.math.gcd but without some checks because we have a stricter range
var x: T = @intCast(p);
var y: T = @intCast(q);
Expand Down
51 changes: 50 additions & 1 deletion src/lib/common/util.zig
Original file line number Diff line number Diff line change
@@ -1,12 +1,61 @@
const std = @import("std");

const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;

const Pointer = if (@hasField(std.builtin.Type, "pointer")) .pointer else .Pointer;

pub fn PointerType(comptime P: type, comptime C: type) type {
return if (@typeInfo(P).Pointer.is_const) *const C else *C;
return if (@field(@typeInfo(P), @tagName(Pointer)).is_const) *const C else *C;
}

test PointerType {
try expectEqual(*bool, PointerType(*u8, bool));
try expectEqual(*const f64, PointerType(*const i32, f64));
}

pub fn isPointerTo(p: anytype, comptime P: type) bool {
const info = @typeInfo(@TypeOf(p));
return switch (info) {
Pointer => @field(info, @tagName(Pointer)).child == P,
else => false,
};
}

test isPointerTo {
const S = struct {};
const s: S = .{};
try expect(!isPointerTo(s, S));
try expect(isPointerTo(&s, S));
}

// NOTE: std.mem.bytesAsValue backported from ziglang/zig#18061
pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, @TypeOf(bytes)) {
return @as(BytesAsValueReturnType(T, @TypeOf(bytes)), @ptrCast(bytes));
}

fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
return CopyPtrAttrs(B, .One, T);
}

fn CopyPtrAttrs(
comptime source: type,
comptime size: std.builtin.Type.Pointer.Size,
comptime child: type,
) type {
const info = @field(@typeInfo(source), @tagName(Pointer));
const args = .{
.size = size,
.is_const = info.is_const,
.is_volatile = info.is_volatile,
.is_allowzero = info.is_allowzero,
.alignment = info.alignment,
.address_space = info.address_space,
.child = child,
.sentinel = null,
};
return @Type(if (@hasField(std.builtin.Type, "pointer"))
.{ .pointer = args }
else
.{ .Pointer = args });
}
10 changes: 7 additions & 3 deletions src/lib/gen1/calc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const Optional = optional.Optional;
const Rational = rational.Rational;

const PointerType = util.PointerType;
const isPointerTo = util.isPointerTo;

const Actions = chance.Actions;
const Action = chance.Action;
Expand All @@ -39,6 +40,9 @@ const Durations = chance.Durations;
const tty = true; // DEBUG
const summary = false; // DEBUG

const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;

/// Information relevant to damage calculation that occured during a Generation I battle `update`.
pub const Summaries = extern struct {
/// Relevant information for Player 1.
Expand All @@ -52,7 +56,7 @@ pub const Summaries = extern struct {

/// Returns the `Summary` for the given `player`.
pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Summary) {
assert(@typeInfo(@TypeOf(self)).Pointer.child == Summaries);
assert(isPointerTo(self, Summaries));
return if (player == .P1) &self.p1 else &self.p2;
}
};
Expand Down Expand Up @@ -105,8 +109,8 @@ pub const Calc = struct {

const val = @field(self.overrides.get(player), @tagName(field));
return if (switch (@typeInfo(@TypeOf(val))) {
.Enum => val != .None,
.Int => val != 0,
Enum => val != .None,
Int => val != 0,
else => unreachable,
}) val else null;
}
Expand Down
Loading

0 comments on commit 5911940

Please sign in to comment.