StaticStringMap and Zon

Preamble

Just wanted to share an interesting pattern I came across which helped solved a problem. Also wanted to invite any feedback and alternative suggestions!

The Problem

In the recent raylib 6.0 release I noticed that the wasm32-emscripten examples were somewhat broken when building with Zig. The code compiled fine, but the runtime couldn’t find any of the resources including textures, shaders, and models. Raylib’s standard C Makefile passes a list of each resource it needs to Emscripten so that it can be preloaded and made available by Emscripten’s virtual file system. Unfortunately the build.zig does not do this, leaving many of the examples lacking.

I wanted to come up a fix where a list of all resources was explicitly provided (as opposed to just having buid.zig run the Makefile.web), but also not bloat the build.zig with a bunch of code just to handle the examples.

StaticStringMap and Zon

I wanted to list the resources inside a Zon file. Partly because it was explicit and easy to edit, plus it allows for modifying of the resources without editing of the build.zig. (I briefly considered .json but :face_vomiting:) However I was a bit stuck on how to lookup data in the Zon file programatically without adding a bunch of parsing logic to the build.zig. I toyed with some meta programming, inspecting the imported Zon, and using inline for to build a HashMap, but that’s when I came across the StaticStringMap.

Assuming a Zon file with the following structure -

.{
    .{
        "core_input_gamepad",
        .{
            .{
                .src_path = "examples/core/resources/ps3.png",
                .virtual_path = "resources/ps3.png",
            },
            .{
                .src_path = "examples/core/resources/xbox.png",
                .virtual_path = "resources/xbox.png",
            },
        },
    },
    .{
        "core_text_file_loading",
        .{
            .{
                .src_path = "examples/core/resources/text_file.txt",
                .virtual_path = "resources/text_file.txt",
            },
        },
    },
   ...
}

We can rely on anonymous array/struct literals of the Zon to map directly into our StaticStringMap -

const EmccExamplesPreloadMap = std.static_string_map.StaticStringMap([]const emsdk.zemscripten.EmccFilePath);
const EmccExamplesPreloadKV = struct { []const u8, []const emsdk.zemscripten.EmccFilePath };
const emcc_examples_preloads: []const EmccExamplesPreloadKV = @import("examples/example_resources.zon");
const emcc_examples_preloads_map = EmccExamplesPreloadMap.initComptime(emcc_examples_preloads);

Then we can just do a simple map look up to see if there is any resources we need to preload

.preload_paths = emcc_examples_preloads_map.get(filename) orelse &.{},

It ended up being a nice compact way in the code to fetch resources from a zon file.

7 Likes