module: update to latest Zig + unify object ID validation/unpacking
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
8a61c70409
commit
59bbea454a
1 changed files with 44 additions and 53 deletions
|
|
@ -138,7 +138,7 @@ pub fn Objects(comptime T: type) type {
|
||||||
objs.internal.mu.unlock();
|
objs.internal.mu.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn new(objs: *@This(), value: T) std.mem.Allocator.Error!ObjectID {
|
pub fn new(objs: *@This(), value: T) std.mem.Allocator.Error!ObjectID {
|
||||||
const allocator = objs.internal.allocator;
|
const allocator = objs.internal.allocator;
|
||||||
const data = &objs.internal.data;
|
const data = &objs.internal.data;
|
||||||
const dead = &objs.internal.dead;
|
const dead = &objs.internal.dead;
|
||||||
|
|
@ -184,50 +184,24 @@ pub fn Objects(comptime T: type) type {
|
||||||
|
|
||||||
pub fn set(objs: *@This(), id: ObjectID, value: T) void {
|
pub fn set(objs: *@This(), id: ObjectID, value: T) void {
|
||||||
const data = &objs.internal.data;
|
const data = &objs.internal.data;
|
||||||
const dead = &objs.internal.dead;
|
|
||||||
const generation = &objs.internal.generation;
|
|
||||||
|
|
||||||
const unpacked: PackedID = @bitCast(id);
|
const unpacked = objs.validateAndUnpack(id, "set");
|
||||||
if (unpacked.generation != generation.items[unpacked.index]) {
|
|
||||||
@panic("mach: set() called with an object that is no longer valid");
|
|
||||||
}
|
|
||||||
if (dead.isSet(unpacked.index)) {
|
|
||||||
@panic("mach: set() called on a dead object");
|
|
||||||
}
|
|
||||||
data.set(unpacked.index, value);
|
data.set(unpacked.index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(objs: *@This(), id: ObjectID) ?T {
|
pub fn get(objs: *@This(), id: ObjectID) ?T {
|
||||||
const data = &objs.internal.data;
|
const data = &objs.internal.data;
|
||||||
const dead = &objs.internal.dead;
|
|
||||||
const generation = &objs.internal.generation;
|
|
||||||
|
|
||||||
const unpacked: PackedID = @bitCast(id);
|
const unpacked = objs.validateAndUnpack(id, "get");
|
||||||
if (unpacked.generation != generation.items[unpacked.index]) {
|
|
||||||
@panic("mach: get() called with an object that is no longer valid");
|
|
||||||
}
|
|
||||||
if (dead.isSet(unpacked.index)) {
|
|
||||||
@panic("mach: get() called on a dead object");
|
|
||||||
}
|
|
||||||
return data.get(unpacked.index);
|
return data.get(unpacked.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(objs: *@This(), id: ObjectID) void {
|
pub fn delete(objs: *@This(), id: ObjectID) void {
|
||||||
const data = &objs.internal.data;
|
const data = &objs.internal.data;
|
||||||
const dead = &objs.internal.dead;
|
const dead = &objs.internal.dead;
|
||||||
const generation = &objs.internal.generation;
|
|
||||||
const recycling_bin = &objs.internal.recycling_bin;
|
const recycling_bin = &objs.internal.recycling_bin;
|
||||||
|
|
||||||
// TODO(object): decide whether to disable safety checks like this in some conditions,
|
const unpacked = objs.validateAndUnpack(id, "delete");
|
||||||
// e.g. in release builds
|
|
||||||
const unpacked: PackedID = @bitCast(id);
|
|
||||||
if (unpacked.generation != generation.items[unpacked.index]) {
|
|
||||||
@panic("mach: delete() called with an object that is no longer valid");
|
|
||||||
}
|
|
||||||
if (dead.isSet(unpacked.index)) {
|
|
||||||
@panic("mach: delete() called on a dead object");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recycling_bin.items.len < recycling_bin.capacity) {
|
if (recycling_bin.items.len < recycling_bin.capacity) {
|
||||||
recycling_bin.appendAssumeCapacity(unpacked.index);
|
recycling_bin.appendAssumeCapacity(unpacked.index);
|
||||||
} else objs.internal.thrown_on_the_floor += 1;
|
} else objs.internal.thrown_on_the_floor += 1;
|
||||||
|
|
@ -242,6 +216,22 @@ pub fn Objects(comptime T: type) type {
|
||||||
.objs = objs,
|
.objs = objs,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validateAndUnpack(objs: *@This(), id: ObjectID, comptime fn_name: []const u8) PackedID {
|
||||||
|
const dead = &objs.internal.dead;
|
||||||
|
const generation = &objs.internal.generation;
|
||||||
|
|
||||||
|
// TODO(object): decide whether to disable safety checks like this in some conditions,
|
||||||
|
// e.g. in release builds
|
||||||
|
const unpacked: PackedID = @bitCast(id);
|
||||||
|
if (unpacked.generation != generation.items[unpacked.index]) {
|
||||||
|
@panic("mach: " ++ fn_name ++ "() called with an object that is no longer valid");
|
||||||
|
}
|
||||||
|
if (dead.isSet(unpacked.index)) {
|
||||||
|
@panic("mach: " ++ fn_name ++ "() called on a dead object");
|
||||||
|
}
|
||||||
|
return unpacked;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -288,7 +278,7 @@ pub fn ModFunctionIDs(comptime Module: type) type {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Struct = .{
|
.@"struct" = .{
|
||||||
.layout = .auto,
|
.layout = .auto,
|
||||||
.is_tuple = false,
|
.is_tuple = false,
|
||||||
.fields = fields,
|
.fields = fields,
|
||||||
|
|
@ -309,7 +299,7 @@ fn ModuleFunctionName2(comptime M: type) type {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Enum = .{
|
.@"enum" = .{
|
||||||
.tag_type = if (enum_fields.len > 0) std.math.IntFittingRange(0, enum_fields.len - 1) else u0,
|
.tag_type = if (enum_fields.len > 0) std.math.IntFittingRange(0, enum_fields.len - 1) else u0,
|
||||||
.fields = enum_fields,
|
.fields = enum_fields,
|
||||||
.decls = &[_]std.builtin.Type.Declaration{},
|
.decls = &[_]std.builtin.Type.Declaration{},
|
||||||
|
|
@ -347,7 +337,7 @@ pub fn Modules(module_lists: anytype) type {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Enum = .{
|
.@"enum" = .{
|
||||||
.tag_type = if (enum_fields.len > 0) std.math.IntFittingRange(0, enum_fields.len - 1) else u0,
|
.tag_type = if (enum_fields.len > 0) std.math.IntFittingRange(0, enum_fields.len - 1) else u0,
|
||||||
.fields = enum_fields,
|
.fields = enum_fields,
|
||||||
.decls = &[_]std.builtin.Type.Declaration{},
|
.decls = &[_]std.builtin.Type.Declaration{},
|
||||||
|
|
@ -360,13 +350,14 @@ pub fn Modules(module_lists: anytype) type {
|
||||||
var m: @This() = .{
|
var m: @This() = .{
|
||||||
.mods = undefined,
|
.mods = undefined,
|
||||||
};
|
};
|
||||||
inline for (@typeInfo(@TypeOf(m.mods)).Struct.fields) |field| {
|
// TODO(object): errdefer release allocations made in this loop
|
||||||
|
inline for (@typeInfo(@TypeOf(m.mods)).@"struct".fields) |field| {
|
||||||
// TODO(objects): module-state-init
|
// TODO(objects): module-state-init
|
||||||
const Mod2 = @TypeOf(@field(m.mods, field.name));
|
const Mod2 = @TypeOf(@field(m.mods, field.name));
|
||||||
var mod: Mod2 = undefined;
|
var mod: Mod2 = undefined;
|
||||||
const module_name_id = try m.module_names.indexOrPut(allocator, @tagName(Mod2.mach_module));
|
const module_name_id = try m.module_names.indexOrPut(allocator, @tagName(Mod2.mach_module));
|
||||||
inline for (@typeInfo(@TypeOf(mod)).Struct.fields) |mod_field| {
|
inline for (@typeInfo(@TypeOf(mod)).@"struct".fields) |mod_field| {
|
||||||
if (@typeInfo(mod_field.type) == .Struct and @hasDecl(mod_field.type, "IsMachObjects")) {
|
if (@typeInfo(mod_field.type) == .@"struct" and @hasDecl(mod_field.type, "IsMachObjects")) {
|
||||||
const object_name_id = try m.module_names.indexOrPut(allocator, mod_field.name);
|
const object_name_id = try m.module_names.indexOrPut(allocator, mod_field.name);
|
||||||
|
|
||||||
// TODO: use packed struct(TypeID) here. Same thing, just get the type from central location
|
// TODO: use packed struct(TypeID) here. Same thing, just get the type from central location
|
||||||
|
|
@ -394,7 +385,7 @@ pub fn Modules(module_lists: anytype) type {
|
||||||
|
|
||||||
pub fn Module(module_tag_or_type: anytype) type {
|
pub fn Module(module_tag_or_type: anytype) type {
|
||||||
const module_name: ModuleName = blk: {
|
const module_name: ModuleName = blk: {
|
||||||
if (@typeInfo(@TypeOf(module_tag_or_type)) == .EnumLiteral or @typeInfo(@TypeOf(module_tag_or_type)) == .Enum) break :blk @as(ModuleName, module_tag_or_type);
|
if (@typeInfo(@TypeOf(module_tag_or_type)) == .enum_literal or @typeInfo(@TypeOf(module_tag_or_type)) == .@"enum") break :blk @as(ModuleName, module_tag_or_type);
|
||||||
validate(module_tag_or_type);
|
validate(module_tag_or_type);
|
||||||
break :blk module_tag_or_type.mach_module;
|
break :blk module_tag_or_type.mach_module;
|
||||||
};
|
};
|
||||||
|
|
@ -423,7 +414,7 @@ pub fn Modules(module_lists: anytype) type {
|
||||||
const f = @field(module, @tagName(fn_name));
|
const f = @field(module, @tagName(fn_name));
|
||||||
const F = @TypeOf(f);
|
const F = @TypeOf(f);
|
||||||
|
|
||||||
if (@typeInfo(F) == .Struct and @typeInfo(F).Struct.is_tuple) {
|
if (@typeInfo(F) == .@"struct" and @typeInfo(F).@"struct".is_tuple) {
|
||||||
// Run a list of functions instead of a single function
|
// Run a list of functions instead of a single function
|
||||||
// TODO: verify this is a mach.schedule() decl
|
// TODO: verify this is a mach.schedule() decl
|
||||||
if (module_name != .app) @compileLog(module_name);
|
if (module_name != .app) @compileLog(module_name);
|
||||||
|
|
@ -438,9 +429,9 @@ pub fn Modules(module_lists: anytype) type {
|
||||||
|
|
||||||
// Inject arguments
|
// Inject arguments
|
||||||
var args: std.meta.ArgsTuple(F) = undefined;
|
var args: std.meta.ArgsTuple(F) = undefined;
|
||||||
outer: inline for (@typeInfo(std.meta.ArgsTuple(F)).Struct.fields) |arg| {
|
outer: inline for (@typeInfo(std.meta.ArgsTuple(F)).@"struct".fields) |arg| {
|
||||||
if (@typeInfo(arg.type) == .Pointer and
|
if (@typeInfo(arg.type) == .pointer and
|
||||||
@typeInfo(std.meta.Child(arg.type)) == .Struct and
|
@typeInfo(std.meta.Child(arg.type)) == .@"struct" and
|
||||||
comptime isValid(std.meta.Child(arg.type)))
|
comptime isValid(std.meta.Child(arg.type)))
|
||||||
{
|
{
|
||||||
// *Module argument
|
// *Module argument
|
||||||
|
|
@ -448,7 +439,7 @@ pub fn Modules(module_lists: anytype) type {
|
||||||
@field(args, arg.name) = &@field(m.mods, @tagName(std.meta.Child(arg.type).mach_module));
|
@field(args, arg.name) = &@field(m.mods, @tagName(std.meta.Child(arg.type).mach_module));
|
||||||
continue :outer;
|
continue :outer;
|
||||||
}
|
}
|
||||||
if (@typeInfo(arg.type) == .Struct and @hasDecl(arg.type, "IsMachMod")) {
|
if (@typeInfo(arg.type) == .@"struct" and @hasDecl(arg.type, "IsMachMod")) {
|
||||||
const M = arg.type.Module;
|
const M = arg.type.Module;
|
||||||
var mv: Mod(M) = .{
|
var mv: Mod(M) = .{
|
||||||
.id = undefined,
|
.id = undefined,
|
||||||
|
|
@ -469,10 +460,10 @@ pub fn Modules(module_lists: anytype) type {
|
||||||
@compileError("mach: function " ++ debug_name ++ " has an invalid argument(" ++ arg.name ++ ") type: " ++ @typeName(arg.type));
|
@compileError("mach: function " ++ debug_name ++ " has an invalid argument(" ++ arg.name ++ ") type: " ++ @typeName(arg.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
const Ret = @typeInfo(F).Fn.return_type orelse void;
|
const Ret = @typeInfo(F).@"fn".return_type orelse void;
|
||||||
switch (@typeInfo(Ret)) {
|
switch (@typeInfo(Ret)) {
|
||||||
// TODO: define error handling of runnable functions
|
// TODO: define error handling of runnable functions
|
||||||
.ErrorUnion => @call(.auto, f, args) catch |err| std.debug.panic("error: {s}", .{@errorName(err)}),
|
.error_union => @call(.auto, f, args) catch |err| std.debug.panic("error: {s}", .{@errorName(err)}),
|
||||||
else => @call(.auto, f, args),
|
else => @call(.auto, f, args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -504,12 +495,12 @@ pub fn Modules(module_lists: anytype) type {
|
||||||
/// Validates that the given struct is a Mach module.
|
/// Validates that the given struct is a Mach module.
|
||||||
fn validate(comptime module: anytype) void {
|
fn validate(comptime module: anytype) void {
|
||||||
if (!@hasDecl(module, "mach_module")) @compileError("mach: invalid module, missing `pub const mach_module = .foo_name;` declaration: " ++ @typeName(@TypeOf(module)));
|
if (!@hasDecl(module, "mach_module")) @compileError("mach: invalid module, missing `pub const mach_module = .foo_name;` declaration: " ++ @typeName(@TypeOf(module)));
|
||||||
if (@typeInfo(@TypeOf(module.mach_module)) != .EnumLiteral) @compileError("mach: invalid module, expected `pub const mach_module = .foo_name;` declaration, found: " ++ @typeName(@TypeOf(module.mach_module)));
|
if (@typeInfo(@TypeOf(module.mach_module)) != .enum_literal) @compileError("mach: invalid module, expected `pub const mach_module = .foo_name;` declaration, found: " ++ @typeName(@TypeOf(module.mach_module)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isValid(comptime module: anytype) bool {
|
fn isValid(comptime module: anytype) bool {
|
||||||
if (!@hasDecl(module, "mach_module")) return false;
|
if (!@hasDecl(module, "mach_module")) return false;
|
||||||
if (@typeInfo(@TypeOf(module.mach_module)) != .EnumLiteral) return false;
|
if (@typeInfo(@TypeOf(module.mach_module)) != .enum_literal) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,7 +513,7 @@ fn NameEnum(comptime mods: anytype) type {
|
||||||
enum_fields = enum_fields ++ [_]std.builtin.Type.EnumField{.{ .name = @tagName(module.mach_module), .value = i }};
|
enum_fields = enum_fields ++ [_]std.builtin.Type.EnumField{.{ .name = @tagName(module.mach_module), .value = i }};
|
||||||
}
|
}
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Enum = .{
|
.@"enum" = .{
|
||||||
.tag_type = std.math.IntFittingRange(0, enum_fields.len - 1),
|
.tag_type = std.math.IntFittingRange(0, enum_fields.len - 1),
|
||||||
.fields = enum_fields,
|
.fields = enum_fields,
|
||||||
.decls = &[_]std.builtin.Type.Declaration{},
|
.decls = &[_]std.builtin.Type.Declaration{},
|
||||||
|
|
@ -552,13 +543,13 @@ fn moduleTuple(comptime tuple: anytype) ModuleTuple(tuple) {
|
||||||
|
|
||||||
/// Type-returning variant of merge()
|
/// Type-returning variant of merge()
|
||||||
fn ModuleTuple(comptime tuple: anytype) type {
|
fn ModuleTuple(comptime tuple: anytype) type {
|
||||||
if (@typeInfo(@TypeOf(tuple)) != .Struct or !@typeInfo(@TypeOf(tuple)).Struct.is_tuple) {
|
if (@typeInfo(@TypeOf(tuple)) != .@"struct" or !@typeInfo(@TypeOf(tuple)).@"struct".is_tuple) {
|
||||||
@compileError("Expected to find a tuple, found: " ++ @typeName(@TypeOf(tuple)));
|
@compileError("Expected to find a tuple, found: " ++ @typeName(@TypeOf(tuple)));
|
||||||
}
|
}
|
||||||
|
|
||||||
var tuple_fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};
|
var tuple_fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};
|
||||||
loop: inline for (tuple) |elem| {
|
loop: inline for (tuple) |elem| {
|
||||||
if (@typeInfo(@TypeOf(elem)) == .Type and @typeInfo(elem) == .Struct) {
|
if (@typeInfo(@TypeOf(elem)) == .type and @typeInfo(elem) == .@"struct") {
|
||||||
// Struct type
|
// Struct type
|
||||||
validate(elem);
|
validate(elem);
|
||||||
for (tuple_fields) |field| if (@as(*const type, @ptrCast(field.default_value.?)).* == elem)
|
for (tuple_fields) |field| if (@as(*const type, @ptrCast(field.default_value.?)).* == elem)
|
||||||
|
|
@ -572,7 +563,7 @@ fn ModuleTuple(comptime tuple: anytype) type {
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = if (@sizeOf(elem) > 0) @alignOf(elem) else 0,
|
.alignment = if (@sizeOf(elem) > 0) @alignOf(elem) else 0,
|
||||||
}};
|
}};
|
||||||
} else if (@typeInfo(@TypeOf(elem)) == .Struct and @typeInfo(@TypeOf(elem)).Struct.is_tuple) {
|
} else if (@typeInfo(@TypeOf(elem)) == .@"struct" and @typeInfo(@TypeOf(elem)).@"struct".is_tuple) {
|
||||||
// Nested tuple
|
// Nested tuple
|
||||||
inline for (moduleTuple(elem)) |nested| {
|
inline for (moduleTuple(elem)) |nested| {
|
||||||
validate(nested);
|
validate(nested);
|
||||||
|
|
@ -593,7 +584,7 @@ fn ModuleTuple(comptime tuple: anytype) type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Struct = .{
|
.@"struct" = .{
|
||||||
.is_tuple = true,
|
.is_tuple = true,
|
||||||
.layout = .auto,
|
.layout = .auto,
|
||||||
.decls = &.{},
|
.decls = &.{},
|
||||||
|
|
@ -616,7 +607,7 @@ fn ModuleTypesByName(comptime modules: anytype) type {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Struct = .{
|
.@"struct" = .{
|
||||||
.layout = .auto,
|
.layout = .auto,
|
||||||
.is_tuple = false,
|
.is_tuple = false,
|
||||||
.fields = fields,
|
.fields = fields,
|
||||||
|
|
@ -639,7 +630,7 @@ fn ModulesByName(comptime modules: anytype) type {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Struct = .{
|
.@"struct" = .{
|
||||||
.layout = .auto,
|
.layout = .auto,
|
||||||
.is_tuple = false,
|
.is_tuple = false,
|
||||||
.fields = fields,
|
.fields = fields,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue