#import "modules/std.sx";

// --- State(T) — a handle to persistent storage ---

State :: struct ($T: Type) {
    ptr: *T;

    get :: (self: State(T)) -> T { self.ptr.*; }

    set :: (self: State(T), val: T) { self.ptr.* = val; }
}

// --- StateEntry — type-erased storage ---

StateEntry :: struct {
    id: s64;
    data: [*]u8;
    size: s64;
    generation: s64;
}

// --- StateStore — manages persistent state ---

StateStore :: struct {
    entries: List(StateEntry);
    current_generation: s64;
    parent_allocator: Allocator;

    init :: (self: *StateStore) {
        self.entries = List(StateEntry).{};
        self.current_generation = 0;
        self.parent_allocator = context.allocator;
    }

    get_or_create :: (self: *StateStore, id: s64, $T: Type, default: T) -> State(T) {
        // Search for existing entry
        i : s64 = 0;
        while i < self.entries.len {
            if self.entries.items[i].id == id {
                self.entries.items[i].generation = self.current_generation;
                return State(T).{ ptr = xx self.entries.items[i].data };
            }
            i += 1;
        }

        // Create new entry
        data : [*]u8 = xx self.parent_allocator.alloc(size_of(T));
        memcpy(data, @default, size_of(T));
        self.entries.append(.{
            id = id,
            data = data,
            size = size_of(T),
            generation = self.current_generation
        }, self.parent_allocator);
        State(T).{ ptr = xx data };
    }

    next_frame :: (self: *StateStore) {
        self.current_generation += 1;
    }
}
