171 lines
4.3 KiB
Zig
171 lines
4.3 KiB
Zig
|
|
// --- LIBS ---
|
||
|
|
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 return error.ResourceNotSet;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// ----------------------------------------------------
|
||
|
|
/// Example
|
||
|
|
/// ```
|
||
|
|
/// const res = try app.resources.getMany(struct {
|
||
|
|
/// server: ?*const Server,
|
||
|
|
/// client: ?*const Client,
|
||
|
|
/// player: *Entity,
|
||
|
|
/// });
|
||
|
|
/// ```
|
||
|
|
/// ----------------------------------------------------
|
||
|
|
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
|
||
|
|
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));
|
||
|
|
}
|