module: support merging module lists
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
b37ece1b9a
commit
95c9ae5278
9 changed files with 130 additions and 34 deletions
|
|
@ -3,8 +3,7 @@ const mach = @import("mach");
|
||||||
// The global list of Mach modules registered for use in our application.
|
// The global list of Mach modules registered for use in our application.
|
||||||
pub const modules = .{
|
pub const modules = .{
|
||||||
mach.Core,
|
mach.Core,
|
||||||
mach.gfx.Sprite,
|
mach.gfx.sprite_modules,
|
||||||
mach.gfx.SpritePipeline,
|
|
||||||
@import("App.zig"),
|
@import("App.zig"),
|
||||||
@import("Glyphs.zig"),
|
@import("Glyphs.zig"),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ const mach = @import("mach");
|
||||||
// The global list of Mach modules registered for use in our application.
|
// The global list of Mach modules registered for use in our application.
|
||||||
pub const modules = .{
|
pub const modules = .{
|
||||||
mach.Core,
|
mach.Core,
|
||||||
mach.gfx.Sprite,
|
mach.gfx.sprite_modules,
|
||||||
mach.gfx.SpritePipeline,
|
|
||||||
@import("App.zig"),
|
@import("App.zig"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,7 @@ const mach = @import("mach");
|
||||||
// The global list of Mach modules registered for use in our application.
|
// The global list of Mach modules registered for use in our application.
|
||||||
pub const modules = .{
|
pub const modules = .{
|
||||||
mach.Core,
|
mach.Core,
|
||||||
mach.gfx.Text,
|
mach.gfx.text_modules,
|
||||||
mach.gfx.TextPipeline,
|
|
||||||
mach.gfx.TextStyle,
|
|
||||||
@import("App.zig"),
|
@import("App.zig"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,15 @@ pub const Text = @import("Text.zig");
|
||||||
pub const TextPipeline = @import("TextPipeline.zig");
|
pub const TextPipeline = @import("TextPipeline.zig");
|
||||||
pub const TextStyle = @import("TextStyle.zig");
|
pub const TextStyle = @import("TextStyle.zig");
|
||||||
|
|
||||||
|
/// All Sprite rendering modules
|
||||||
|
pub const sprite_modules = .{ Sprite, SpritePipeline };
|
||||||
|
|
||||||
|
/// All Text rendering modules
|
||||||
|
pub const text_modules = .{ Text, TextPipeline, TextStyle };
|
||||||
|
|
||||||
|
/// All graphics modules
|
||||||
|
pub const modules = .{ sprite_modules, text_modules };
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
pub const Font = @import("font/main.zig").Font;
|
pub const Font = @import("font/main.zig").Font;
|
||||||
pub const TextRun = @import("font/main.zig").TextRun;
|
pub const TextRun = @import("font/main.zig").TextRun;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,10 @@ pub const modules = blk: {
|
||||||
if (!@hasDecl(@import("root"), "modules")) {
|
if (!@hasDecl(@import("root"), "modules")) {
|
||||||
@compileError("expected `pub const modules = .{};` in root file");
|
@compileError("expected `pub const modules = .{};` in root file");
|
||||||
}
|
}
|
||||||
break :blk @import("root").modules;
|
break :blk merge(.{
|
||||||
|
builtin_modules,
|
||||||
|
@import("root").modules,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
pub const ModSet = @import("module/main.zig").ModSet;
|
pub const ModSet = @import("module/main.zig").ModSet;
|
||||||
pub const Modules = @import("module/main.zig").Modules(modules);
|
pub const Modules = @import("module/main.zig").Modules(modules);
|
||||||
|
|
@ -35,6 +38,9 @@ pub const Archetype = @import("module/main.zig").Archetype;
|
||||||
pub const ModuleID = @import("module/main.zig").ModuleID;
|
pub const ModuleID = @import("module/main.zig").ModuleID;
|
||||||
pub const EventID = @import("module/main.zig").EventID;
|
pub const EventID = @import("module/main.zig").EventID;
|
||||||
pub const AnyEvent = @import("module/main.zig").AnyEvent;
|
pub const AnyEvent = @import("module/main.zig").AnyEvent;
|
||||||
|
pub const merge = @import("module/main.zig").merge;
|
||||||
|
pub const builtin_modules = @import("module/main.zig").builtin_modules;
|
||||||
|
pub const EntityModule = @import("module/main.zig").EntityModule;
|
||||||
|
|
||||||
/// To use experimental sysgpu graphics API, you can write this in your main.zig:
|
/// To use experimental sysgpu graphics API, you can write this in your main.zig:
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ const query_mod = @import("query.zig");
|
||||||
const Archetype = @import("Archetype.zig");
|
const Archetype = @import("Archetype.zig");
|
||||||
const StringTable = @import("StringTable.zig");
|
const StringTable = @import("StringTable.zig");
|
||||||
const ComponentTypesByName = @import("module.zig").ComponentTypesByName;
|
const ComponentTypesByName = @import("module.zig").ComponentTypesByName;
|
||||||
|
const merge = @import("main.zig").merge;
|
||||||
|
const builtin_modules = @import("main.zig").builtin_modules;
|
||||||
|
|
||||||
/// An entity ID uniquely identifies an entity globally within an Entities set.
|
/// An entity ID uniquely identifies an entity globally within an Entities set.
|
||||||
pub const EntityID = u64;
|
pub const EntityID = u64;
|
||||||
|
|
@ -699,7 +701,10 @@ pub fn ArchetypeIterator(comptime component_types_by_name: anytype) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
std.testing.refAllDeclsRecursive(Entities(.{}));
|
const modules = ComponentTypesByName(merge(.{
|
||||||
|
builtin_modules,
|
||||||
|
})){};
|
||||||
|
std.testing.refAllDeclsRecursive(Entities(modules));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: require "one big registration of components" even when using dynamic API? Would alleviate
|
// TODO: require "one big registration of components" even when using dynamic API? Would alleviate
|
||||||
|
|
@ -749,7 +754,8 @@ test "example" {
|
||||||
|
|
||||||
const Rotation = struct { degrees: f32 };
|
const Rotation = struct { degrees: f32 };
|
||||||
|
|
||||||
const component_types_by_name = ComponentTypesByName(.{
|
const component_types_by_name = ComponentTypesByName(merge(.{
|
||||||
|
builtin_modules,
|
||||||
struct {
|
struct {
|
||||||
pub const name = .game;
|
pub const name = .game;
|
||||||
pub const components = .{
|
pub const components = .{
|
||||||
|
|
@ -758,7 +764,7 @@ test "example" {
|
||||||
.rotation = .{ .type = Rotation },
|
.rotation = .{ .type = Rotation },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}){};
|
})){};
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Create a world.
|
// Create a world.
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,19 @@ pub const Modules = @import("module.zig").Modules;
|
||||||
pub const ModuleID = @import("module.zig").ModuleID;
|
pub const ModuleID = @import("module.zig").ModuleID;
|
||||||
pub const EventID = @import("module.zig").EventID;
|
pub const EventID = @import("module.zig").EventID;
|
||||||
pub const AnyEvent = @import("module.zig").AnyEvent;
|
pub const AnyEvent = @import("module.zig").AnyEvent;
|
||||||
|
pub const Merge = @import("module.zig").Merge;
|
||||||
|
pub const merge = @import("module.zig").merge;
|
||||||
|
|
||||||
|
pub const builtin_modules = .{EntityModule};
|
||||||
|
|
||||||
|
/// Builtin .entity module
|
||||||
|
pub const EntityModule = struct {
|
||||||
|
pub const name = .entity;
|
||||||
|
|
||||||
|
pub const components = .{
|
||||||
|
.id = .{ .type = EntityID, .description = "Entity ID" },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
test {
|
test {
|
||||||
std.testing.refAllDeclsRecursive(@This());
|
std.testing.refAllDeclsRecursive(@This());
|
||||||
|
|
@ -23,7 +36,7 @@ test "entities DB" {
|
||||||
const allocator = testing.allocator;
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
const root = struct {
|
const root = struct {
|
||||||
pub const modules = .{ Renderer, Physics };
|
pub const modules = merge(.{ builtin_modules, Renderer, Physics });
|
||||||
|
|
||||||
const Physics = struct {
|
const Physics = struct {
|
||||||
pointer: u8,
|
pointer: u8,
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,78 @@ pub const AnyEvent = struct {
|
||||||
event_id: EventID,
|
event_id: EventID,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Type-returning variant of merge()
|
||||||
|
pub fn Merge(comptime tuple: anytype) type {
|
||||||
|
if (@typeInfo(@TypeOf(tuple)) != .Struct or !@typeInfo(@TypeOf(tuple)).Struct.is_tuple) {
|
||||||
|
@compileError("Expected to find a tuple, found: " ++ @typeName(@TypeOf(tuple)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var tuple_fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};
|
||||||
|
loop: inline for (tuple) |elem| {
|
||||||
|
@setEvalBranchQuota(10_000);
|
||||||
|
if (@typeInfo(@TypeOf(elem)) == .Type and @typeInfo(elem) == .Struct) {
|
||||||
|
// Struct type
|
||||||
|
validateModule(elem, false);
|
||||||
|
for (tuple_fields) |field| if (@as(*const type, @ptrCast(field.default_value.?)).* == elem)
|
||||||
|
continue :loop;
|
||||||
|
|
||||||
|
var num_buf: [128]u8 = undefined;
|
||||||
|
tuple_fields = tuple_fields ++ [_]std.builtin.Type.StructField{.{
|
||||||
|
.name = std.fmt.bufPrintZ(&num_buf, "{d}", .{tuple_fields.len}) catch unreachable,
|
||||||
|
.type = type,
|
||||||
|
.default_value = &elem,
|
||||||
|
.is_comptime = false,
|
||||||
|
.alignment = if (@sizeOf(elem) > 0) @alignOf(elem) else 0,
|
||||||
|
}};
|
||||||
|
} else if (@typeInfo(@TypeOf(elem)) == .Struct and @typeInfo(@TypeOf(elem)).Struct.is_tuple) {
|
||||||
|
// Nested tuple
|
||||||
|
inline for (Merge(elem){}) |Nested| {
|
||||||
|
validateModule(Nested, false);
|
||||||
|
for (tuple_fields) |field| if (@as(*const type, @ptrCast(field.default_value.?)).* == Nested)
|
||||||
|
continue :loop;
|
||||||
|
|
||||||
|
var num_buf: [128]u8 = undefined;
|
||||||
|
tuple_fields = tuple_fields ++ [_]std.builtin.Type.StructField{.{
|
||||||
|
.name = std.fmt.bufPrintZ(&num_buf, "{d}", .{tuple_fields.len}) catch unreachable,
|
||||||
|
.type = type,
|
||||||
|
.default_value = &Nested,
|
||||||
|
.is_comptime = false,
|
||||||
|
.alignment = if (@sizeOf(Nested) > 0) @alignOf(Nested) else 0,
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@compileError("Expected to find a tuple or struct type, found: " ++ @typeName(@TypeOf(elem)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return @Type(.{
|
||||||
|
.Struct = .{
|
||||||
|
.is_tuple = true,
|
||||||
|
.layout = .Auto,
|
||||||
|
.decls = &.{},
|
||||||
|
.fields = tuple_fields,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a tuple of module structs or module struct tuples:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// .{
|
||||||
|
/// .{ Baz, .{ Bar, Foo, .{ Fam } }, Bar },
|
||||||
|
/// Foo,
|
||||||
|
/// Bam,
|
||||||
|
/// .{ Foo, Bam },
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Returns a single tuple type with the struct types deduplicated:
|
||||||
|
///
|
||||||
|
/// .{ Baz, Bar, Foo, Fam, Bar, Bam }
|
||||||
|
///
|
||||||
|
pub fn merge(comptime tuple: anytype) Merge(tuple) {
|
||||||
|
return Merge(tuple){};
|
||||||
|
}
|
||||||
|
|
||||||
/// Manages comptime .{A, B, C} modules and runtime modules.
|
/// Manages comptime .{A, B, C} modules and runtime modules.
|
||||||
pub fn Modules(comptime modules: anytype) type {
|
pub fn Modules(comptime modules: anytype) type {
|
||||||
// Verify that each module is valid.
|
// Verify that each module is valid.
|
||||||
|
|
@ -462,7 +534,7 @@ pub fn Modules(comptime modules: anytype) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ModsByName(comptime modules: anytype) type {
|
fn ModsByName(comptime modules: anytype) type {
|
||||||
var fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};
|
var fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};
|
||||||
for (modules) |M| {
|
for (modules) |M| {
|
||||||
const ModT = ModSet(modules).Mod(M);
|
const ModT = ModSet(modules).Mod(M);
|
||||||
|
|
@ -647,6 +719,11 @@ inline fn injectArgs(comptime Function: type, comptime Injectable: type, injecta
|
||||||
// Argument is declared as injectable, but we do not have a value to inject for it.
|
// Argument is declared as injectable, but we do not have a value to inject for it.
|
||||||
// This can be the case if e.g. a Mod() parameter is specified, but that module is
|
// This can be the case if e.g. a Mod() parameter is specified, but that module is
|
||||||
// not registered.
|
// not registered.
|
||||||
|
//
|
||||||
|
// TODO: we could make this error message less verbose, currently it reads e.g.
|
||||||
|
//
|
||||||
|
// src/module/module.zig:736:13: error: mach: cannot inject argument of type: *module.module.ModSet(.{Core, gfx.Sprite, gfx.SpritePipeline, App, Glyphs}).Mod(Core) - is it registered in your program's top-level `pub const modules = .{};`? used by mach_core.start
|
||||||
|
//
|
||||||
@compileError("mach: cannot inject argument of type: " ++ @typeName(arg.type) ++ " - is it registered in your program's top-level `pub const modules = .{};`? used by " ++ debug_name);
|
@compileError("mach: cannot inject argument of type: " ++ @typeName(arg.type) ++ " - is it registered in your program's top-level `pub const modules = .{};`? used by " ++ debug_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -914,9 +991,6 @@ fn validateEvents(comptime error_prefix: anytype, comptime events: anytype) void
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// struct {
|
/// struct {
|
||||||
/// builtin: struct {
|
|
||||||
/// id: @TypeOf() = .{ .type = EntityID, .description = "Entity ID" },
|
|
||||||
/// },
|
|
||||||
/// physics: struct {
|
/// physics: struct {
|
||||||
/// location: @TypeOf() = .{ .type = Vec3, .description = null },
|
/// location: @TypeOf() = .{ .type = Vec3, .description = null },
|
||||||
/// rotation: @TypeOf() = .{ .type = Vec2, .description = "rotation component" },
|
/// rotation: @TypeOf() = .{ .type = Vec2, .description = "rotation component" },
|
||||||
|
|
@ -938,23 +1012,6 @@ pub fn ComponentTypesByName(comptime modules: anytype) type {
|
||||||
.alignment = @alignOf(MC),
|
.alignment = @alignOf(MC),
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builtin components
|
|
||||||
// TODO: better method of injecting builtin module?
|
|
||||||
const BuiltinMC = ComponentTypesM(struct {
|
|
||||||
pub const name = .builtin;
|
|
||||||
pub const components = .{
|
|
||||||
.id = .{ .type = EntityID, .description = "Entity ID" },
|
|
||||||
};
|
|
||||||
});
|
|
||||||
fields = fields ++ [_]std.builtin.Type.StructField{.{
|
|
||||||
.name = "entity",
|
|
||||||
.type = BuiltinMC,
|
|
||||||
.default_value = &BuiltinMC{},
|
|
||||||
.is_comptime = true,
|
|
||||||
.alignment = @alignOf(BuiltinMC),
|
|
||||||
}};
|
|
||||||
|
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
.Struct = .{
|
.Struct = .{
|
||||||
.layout = .Auto,
|
.layout = .Auto,
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ pub fn Query(comptime component_types_by_name: anytype) type {
|
||||||
const namespaces = std.meta.fields(Namespace);
|
const namespaces = std.meta.fields(Namespace);
|
||||||
var fields: [namespaces.len]std.builtin.Type.UnionField = undefined;
|
var fields: [namespaces.len]std.builtin.Type.UnionField = undefined;
|
||||||
for (namespaces, 0..) |namespace, i| {
|
for (namespaces, 0..) |namespace, i| {
|
||||||
const ns = std.meta.stringToEnum(Namespace, namespace.name).?;
|
const ns = stringToEnum(Namespace, namespace.name).?;
|
||||||
fields[i] = .{
|
fields[i] = .{
|
||||||
.name = namespace.name,
|
.name = namespace.name,
|
||||||
.type = ComponentList(ns),
|
.type = ComponentList(ns),
|
||||||
|
|
@ -61,6 +61,15 @@ pub fn Query(comptime component_types_by_name: anytype) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: cannot use std.meta.stringToEnum for some reason; an issue with its internal comptime map and u0 values
|
||||||
|
pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
|
||||||
|
inline for (@typeInfo(T).Enum.fields) |enumField| {
|
||||||
|
if (std.mem.eql(u8, str, enumField.name)) {
|
||||||
|
return @field(T, enumField.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "query" {
|
test "query" {
|
||||||
const Location = struct {
|
const Location = struct {
|
||||||
x: f32 = 0,
|
x: f32 = 0,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue