NYXA/src/resource/storage.zig

176 lines
4.5 KiB
Zig
Raw Normal View History

2026-08-03 16:54:23 +01:00
//! ----------------------------------------------------
//! ----------------------------------------------------
2026-07-09 22:30:04 +01:00
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;
}
/// ----------------------------------------------------
2026-08-03 16:54:23 +01:00
/// # Example
///
/// ```zig
2026-07-09 22:30:04 +01:00
/// const res = try app.resources.getMany(struct {
2026-08-03 16:54:23 +01:00
/// state: *GameState,
2026-07-09 22:30:04 +01:00
/// server: ?*const Server,
/// client: ?*const Client,
/// });
2026-08-03 16:54:23 +01:00
///
/// res.state.score += 1;
2026-07-09 22:30:04 +01:00
/// ```
/// ----------------------------------------------------
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));
}