Trying to create a little server application

Hi, I’m very new to Zig, coming from Rust, and basically just finished ziglings after a few weekends. Now I want to create my first little project. It is supposed to be a simple server that manages a list of “work”/“resources” that is distributed to clients. A client requests a resource, does some work, and then confirms it did the work, then the server marks it as done. I am having a bit of trouble with the general setup. My idea was to structure it like this:


const Resource = struct {
    work: []u8,
};

// got this idea from https://matklad.github.io/2025/12/23/zig-newtype-index-pattern.html
const ResourceId = enum(u32) {
    _,
};

/// container for resources
const Pool = struct {
    name: []const u8,

    resources: std.HashMap(todo); // all resources, map of ResourceId->Resource

    // lists of IDs to keep the resource states, trying to be data-oriented or something
    free_resources: std.ArrayList(ResourceId),
    pending_resources: std.ArrayList(ResourceId),
    done_resources: std.ArrayList(ResourceId),

};

The “work” is just a string (maybe json, idk yet) that the client will receive.

  1. Resource is supposed to own the work string/data. Is it right to use a u8 slice for this case? Because my understanding of a slice is that it can point to any part of e.g. a string. How would I be sure that the resource instance owns this? E.g. when I free a Resource instance, I could not safely free the slice, because it could have been created from anything.
  2. For something like a Pool which should be dynamically allocated, is there a convention for naming a “constructor” method (e.g. init)? Is it even normal to have such a method? I think you would have to pass it an allocator, right?
  3. My whole approach feels a bit weird, perhaps because I cannot see the bigger picture due to missing experience.

These are really just the first few lines I wrote and I already have a lot of questions :sweat_smile:.. For me it is definitely harder than Rust, but maybe it is just beginner’s paralysis.. Thank you for any help!!

Hey, welcome to ziggit! (-:

First the easy part:

For something like a Pool which should be dynamically allocated, is there a convention for naming a “constructor” method (e.g. init)? Is it even normal to have such a method? I think you would have to pass it an allocator, right?

Yes, fn init(gpa: Allocator, …) Pool is perfectly fine and the common approach. If you want to allocate & initialize a Pool (which you rarely need in one step), the convention is fn create(gpa: Allocator, …) *Pool

Resource is supposed to own the work string/data. Is it right to use a u8 slice for this case? Because my understanding of a slice is that it can point to any part of e.g. a string. How would I be sure that the resource instance owns this? E.g. when I free a Resource instance, I could not safely free the slice, because it could have been created from anything.

Yes, just like a pointer, a slice can point to anything. Ownership is not enforced by the compiler, but defined by documentation. You can make this clearer by also have init/deinit on the owning struct e.g.

const Resource = struct {
    work: []u8,

    /// Takes ownership of work. Will free it on deinit.
    fn init(work: []const u8) !Resource {
       return .{ .work = work };
    }

    /// gpa must be the Allocator that allocated the original work
    fn deinit(r: *Resource, gpa: Allocator) void {
        gpa.free(r.work);
    }
};

And similar, you can say that all Resources are owned by Pool – also have a pool.deinit function that loops over all resources and calls resource.deinit. Combined with the usual pattern of

var pool : Pool = .init(gpa, …);
defer pool.deinit(gpa);
  1. My whole approach feels a bit weird, perhaps because I cannot see the bigger picture due to missing experience.

Best way is to implement it, see where you struggle, and potentially redesign. (-: Keep it simple first, and then see where it could be optimized. When you implement it, you’ll may find these questions: when a work is done, it needs to be put from pending_resources to done_resources. With an ArrayList it’s O(n) to find the index in the array. Do you even need to iterate over pending_resources? And when you already have a free list of free_resources, do you need a HashMap? Instead the ResourceID could simply be indices into an array.