//! ---------------------------------------------------- //! ---------------------------------------------------- const std = @import("std"); const Resource = @import("resource.zig"); const TypeID = @import("../template/type_id.zig").of; const Self = @This(); // // FIELDS // data: std.AutoHashMap(u64, Resource), alloc: std.mem.Allocator, /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn init(alloc: std.mem.Allocator) Self { return .{ .data = .init(alloc), .alloc = alloc, }; } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deinit(self: *Self) void { var it = self.data.valueIterator(); while (it.next()) |v| { v.destroy(v.ptr, self.alloc); } self.data.deinit(); } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn set( self: *Self, value: anytype, ) !void { _ = try self.getOrSet(value); } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn remove( self: *Self, comptime T: type, ) void { _ = self.data.remove(TypeID(T)); } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getOrSet( self: *Self, value: anytype, ) !*@TypeOf(value) { // --- DATA --- const T = @TypeOf(value); const id = TypeID(T); // --- RETURN IF ALREADY EXISTS --- if (self.data.getPtr(id)) |res| { const v: *T = @ptrCast(@alignCast(res.ptr)); v.* = value; return v; } // --- NEW PTR --- const ptr = try self.alloc.create(T); errdefer self.alloc.destroy(ptr); // --- ASSIGN VALUE --- ptr.* = value; // --- ADD NEW --- try self.data.put(id, .{ .ptr = ptr, .destroy = struct { pub fn destroy(_ptr: *anyopaque, _alloc: std.mem.Allocator) void { const v: *T = @ptrCast(@alignCast(_ptr)); _alloc.destroy(v); } }.destroy, }); // --- RESULT --- return @ptrCast(@alignCast(ptr)); } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getPtr( self: *Self, comptime T: type, ) ?*T { const res = self.data.getPtr(TypeID(T)) orelse return null; return @ptrCast(@alignCast(res.ptr)); } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getConstPtr( self: *Self, comptime T: type, ) ?*const T { const ptr = self.getPtr(T) orelse return null; return ptr; } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn require( self: *Self, comptime T: type, ) error{ResourceNotSet}!*T { return self.getPtr(T) orelse { std.debug.print("\x1b[31m[RESOURCE_MISSING]\x1b[0m {s}\n", .{@typeName(T)}); return error.ResourceNotSet; }; } /// ---------------------------------------------------- /// # Example /// /// ```zig /// const res = try app.resources.getMany(struct { /// state: *GameState, /// server: ?*const Server, /// client: ?*const Client, /// }); /// /// res.state.score += 1; /// ``` /// ---------------------------------------------------- pub fn getMany( self: *Self, comptime Result: type, ) error{ResourceNotSet}!Result { // --- RESULT --- var result: Result = undefined; // --- GET FIELDS --- inline for (std.meta.fields(Result)) |field| { // --- FIELD INFO --- const FieldType = field.type; switch (@typeInfo(FieldType)) { .optional => |opt| { const ptr_info = @typeInfo(opt.child).pointer; @field(result, field.name) = self.getPtr(ptr_info.child); }, .pointer => |ptr| { @field(result, field.name) = self.getPtr(ptr.child) orelse { std.debug.print("\x1b[31m[RESOURCE_MISSING]\x1b[0m {s}: {s}\n", .{ field.name, @typeName(field.type) }); return error.ResourceNotSet; }; }, else => @compileError( "getMany fields must be *T or ?*T; field '" ++ field.name ++ "' has type '" ++ @typeName(FieldType) ++ "'", ), } } return result; } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn contains( self: *const Self, comptime T: type, ) bool { return self.data.contains(TypeID(T)); }