Mirror of zig-gamedev/zpool for WetGrape offline builds
Find a file
Casey Banner 02d1472cc4
Upgrade to Zig 0.16.x (#5)
- Fixup usages of deprecated @Type builtin
- std.io -> std.Io
- Specify underlying type of packed structs
- Explicit errorsets

---------

Co-authored-by: hazeycode <chris@hazeycode.com>
2026-05-11 20:08:47 +01:00
.github/workflows upgrade setup-zig 2025-07-20 22:46:33 +01:00
src Upgrade to Zig 0.16.x (#5) 2026-05-11 20:08:47 +01:00
.gitignore files from monorepo @ 613d847104a072fc1d4442f58d5f50b3f9c3f27c 2024-11-03 21:55:06 +00:00
build.zig - Fixup build script deprecations (#3) 2025-07-20 10:51:39 +01:00
build.zig.zon Upgrade to Zig 0.16.x (#5) 2026-05-11 20:08:47 +01:00
LICENSE files from monorepo @ 613d847104a072fc1d4442f58d5f50b3f9c3f27c 2024-11-03 21:55:06 +00:00
README.md Update README.md 2024-11-03 21:55:44 +00:00

zpool

Generic pool & handle implementation for Zig. Based on Andre Weissflog's "Handles Are The Better Pointers".

Exposing API resources using pools and handles is a common way to avoid exposing implementation details to calling code and providing some insulation against stale references in data structures maintained by the caller.

When the caller is provided a handle instead of an opaque pointer, the API implementation is free to move resources around, replace them, and even discard them.

Pool(index_bits: u8, cycle_bits: u8, TResource: type, TColumns: type)
Handle(index_bits: u8, cycle_bits: u8, TResource: type)

The generic Pool type has configurable bit distribution for the Handle's index/cycle fields, and supports multiple columns of data to be indexed by a handle, using std.MultiArrayList to store all of the pool data in a single memory allocation. The TResource parameter ensures the pool and handle types can be distinct types even when other parameters are the same.

Getting started

Example build.zig:

pub fn build(b: *std.Build) void {
    const exe = b.addExecutable(.{ ... });

    const zpool = b.dependency("zpool", .{});
    exe.root_module.addImport("zpool", zpool.module("root"));
}

Now in your code you may import and use zpool:

const Pool = @import("zpool").Pool;

const ImagePtr  = graphics.Image;
const ImageInfo = graphics.ImageInfo;

pub const ImagePool = Pool(16, 16, ImagePtr, struct {
    ptr: ImagePtr,
    info: ImageInfo,
});
pub const ImageHandle = ImagePool.Handle;
var imagePool = ImagePool.initMaxCapacity(allocator);
defer pool.deinit();
pub fn acquireImage(info: ImageInfo) !ImageHandle {
    const handle : ImageHandle = try imagePool.add(.{
        .ptr = graphics.createImage(info),
        .info = info,
    });
    return handle;
}

pub fn drawImage(handle: ImageHandle) !void {
    // get the stored ImagePtr
    const ptr : ImagePtr = try imagePool.getColumn(handle, .ptr);
    graphics.drawImage(ptr);
}

pub fn resizeImage(handle: ImageHandle, width: u16, height: u16) !void {
    // get a pointer to the stored ImageInfo
    const info : *ImageInfo = try imagePool.getColumnPtr(handle, .info);
    const old_width = info.width;
    const old_height = info.height;
    const old_pixels = // allocate memory to store old pixels

    // get the stored ImagePtr
    const ptr = try imagePool.getColumn(handle, .ptr);
    graphics.readPixels(ptr, old_pixels);

    const new_pixels = // allocate memory to store new pixels

    super_eagle.resizeImage(
        old_width, old_height, old_pixels,
        new_width, new_height, new_pixels);

    graphics.writePixels(ptr, new_width, new_height, new_pixels);

    // update the stored ImageInfo
    info.width = new_width;
    info.height = new_height;
}