const std = @import("std"); const Render = struct { const depends = .{}; }; const Window = struct { const depends = .{Render}; }; const ImGui = struct { const depends = .{ Render, Window }; }; const App = struct { const depends = .{ImGui}; }; fn append(comptime T: type, comptime list: []const T, comptime val: T) []const T { return list ++ [1]T{val}; } fn contains(comptime T: type, comptime haystack: []const T, comptime needle: T) bool { return std.mem.indexOfScalar(T, haystack, needle) != null; } pub fn dependencies(mod: type) []const type { // todo add a "before" and "after" that impose ordering constraints but don't bring the items in as depednencies. const Ctx = struct { all: []const type = &.{}, mark: []const type = &.{}, fn visit(ctx: *@This(), x: type) void { if (contains(type, ctx.all, x)) return; if (contains(type, ctx.mark, x)) @compileError("cycle"); ctx.mark = append(type, ctx.mark, x); for (x.depends) |dep| ctx.visit(dep); ctx.all = append(type, ctx.all, x); } }; var ctx: Ctx = .{}; ctx.visit(mod); return ctx.all; } pub fn main() !void { inline for (dependencies(App)) |dep| { std.debug.print("{s}\n", .{@typeName(dep)}); } }