153 lines
4.3 KiB
Zig
153 lines
4.3 KiB
Zig
const std = @import("std");
|
|
const json_utils = @import("../json_utils.zig");
|
|
const Store = @import("../store.zig");
|
|
|
|
const assert = std.debug.assert;
|
|
|
|
const SimpleItem = @This();
|
|
|
|
id: Store.Id,
|
|
quantity: u64,
|
|
|
|
pub fn init(id: Store.Id, quantity: u64) SimpleItem {
|
|
return SimpleItem{ .id = id, .quantity = quantity };
|
|
}
|
|
|
|
pub fn parse(store: *Store, slot_obj: std.json.ObjectMap) !?SimpleItem {
|
|
const code = try json_utils.getStringRequired(slot_obj, "code");
|
|
if (code.len == 0) return null;
|
|
|
|
const quantity = try json_utils.getIntegerRequired(slot_obj, "quantity");
|
|
if (quantity < 0) return error.InvalidQuantity;
|
|
|
|
return SimpleItem{
|
|
.id = try store.items.getOrReserveId(code),
|
|
.quantity = @intCast(quantity),
|
|
};
|
|
}
|
|
|
|
pub fn BoundedArray(comptime slot_count: u32) type {
|
|
const Items = std.BoundedArray(SimpleItem, slot_count);
|
|
|
|
return struct {
|
|
items: Items = .{ .len = 0 },
|
|
|
|
pub fn init() @This() {
|
|
return @This(){};
|
|
}
|
|
|
|
pub fn parse(store: *Store, slots_array: std.json.Array) !@This() {
|
|
var slots = Items.init(0) catch unreachable;
|
|
|
|
for (slots_array.items) |slot_value| {
|
|
const slot_obj = json_utils.asObject(slot_value) orelse return error.InvalidType;
|
|
|
|
if (try SimpleItem.parse(store, slot_obj)) |slot| {
|
|
try slots.append(slot);
|
|
}
|
|
}
|
|
|
|
return @This(){ .items = slots };
|
|
}
|
|
|
|
fn findSlotIndex(self: *const @This(), id: Store.Id) ?usize {
|
|
for (0.., self.items.slice()) |i, *slot| {
|
|
if (slot.id == id) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
fn findSlot(self: *@This(), id: Store.Id) ?*SimpleItem {
|
|
if (self.findSlotIndex(id)) |index| {
|
|
return &self.items.buffer[index];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
pub fn remove(self: *@This(), id: Store.Id, quantity: u64) void {
|
|
const slot_index = self.findSlotIndex(id) orelse unreachable;
|
|
const slot = self.items.get(slot_index);
|
|
assert(slot.quantity >= quantity);
|
|
|
|
slot.quantity -= quantity;
|
|
if (slot.quantity == 0) {
|
|
self.items.swapRemove(slot_index);
|
|
}
|
|
}
|
|
|
|
pub fn add(self: *@This(), id: Store.Id, quantity: u64) !void {
|
|
if (quantity == 0) return;
|
|
|
|
if (self.findSlot(id)) |slot| {
|
|
slot.quantity += quantity;
|
|
} else {
|
|
try self.items.append(SimpleItem.init(id, quantity));
|
|
}
|
|
}
|
|
|
|
pub fn addAssumeCapacity(self: *@This(), id: Store.Id, quantity: u64) void {
|
|
if (quantity == 0) return;
|
|
|
|
if (self.findSlot(id)) |slot| {
|
|
slot.quantity += quantity;
|
|
} else {
|
|
self.items.appendAssumeCapacity(SimpleItem.init(id, quantity));
|
|
}
|
|
}
|
|
|
|
pub fn addSlice(self: *@This(), items: []const SimpleItem) !void {
|
|
for (items) |item| {
|
|
try self.add(item.id, item.quantity);
|
|
}
|
|
}
|
|
|
|
pub fn removeSlice(self: *@This(), items: []const SimpleItem) void {
|
|
for (items) |item| {
|
|
self.remove(item.id, item.quantity);
|
|
}
|
|
}
|
|
|
|
pub fn getQuantity(self: *const @This(), id: Store.Id) u64 {
|
|
if (self.findSlotIndex(id)) |index| {
|
|
return self.items.get(index).quantity;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
pub fn totalQuantity(self: *const @This()) u64 {
|
|
var count: u64 = 0;
|
|
for (self.items.constSlice()) |slot| {
|
|
count += slot.quantity;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
pub fn slice(self: @This()) []const SimpleItem {
|
|
return self.items.slice();
|
|
}
|
|
|
|
pub fn format(
|
|
self: @This(),
|
|
comptime fmt: []const u8,
|
|
options: std.fmt.FormatOptions,
|
|
writer: anytype,
|
|
) !void {
|
|
_ = fmt;
|
|
_ = options;
|
|
|
|
try writer.print("{s}{{ ", .{@typeName(@This())});
|
|
|
|
for (self.items.slice()) |item| {
|
|
try writer.print("{}, ", .{item});
|
|
}
|
|
|
|
try writer.writeAll("}");
|
|
}
|
|
};
|
|
}
|