RFC 9562 UUID implementation in Zig
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jeffrey C. Ollie 553a6265f8
All checks were successful
test / test (push) Successful in 6m14s
test / docs (push) Successful in 7m9s
add CONTRIBUTING.md and say where to report issues
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XEKu5bD11ZA5F6wx1XPeCf
2026-10-14 02:19:35 -05:00
.forgejo/workflows bring the Forgejo workflow in line with the template 2026-10-02 17:31:46 -05:00
LICENSES update licensing, add tangled workflow 2026-05-19 22:20:08 -05:00
src add the Windows registry form and UUID.fromName 2026-10-14 02:17:33 -05:00
.gitignore update licensing, add tangled workflow 2026-05-19 22:20:08 -05:00
build.zig update to Zig 0.17.0 2026-10-02 17:31:46 -05:00
build.zig.zon add the Windows registry form and UUID.fromName 2026-10-14 02:17:33 -05:00
CONTRIBUTING.md add CONTRIBUTING.md and say where to report issues 2026-10-14 02:19:35 -05:00
flake.lock update to Zig 0.17.0 2026-10-02 17:31:46 -05:00
flake.nix update to Zig 0.17.0 2026-10-02 17:31:46 -05:00
README.md add CONTRIBUTING.md and say where to report issues 2026-10-14 02:19:35 -05:00
REUSE.toml update licensing, add tangled workflow 2026-05-19 22:20:08 -05:00

RFC 9562 UUIDs for Zig

A Zig library for generating, parsing, and formatting RFC 9562 UUIDs.

The API documentation, generated from the doc comments in the source, is published at https://jeff.jcollie.page/zig-uuid/.

Features

  • Generate version 1, 2, 3, 4, 5, 6, 7, and 8 UUIDs
  • The special nil (all zeros) and max (all ones) UUIDs
  • The well-known name space IDs (DNS, URL, OID, X.500) for creating v3 and v5 UUIDs
  • Create v3 and v5 UUIDs straight from a name space and a name with UUID.fromName, which does the hashing; the name can be given in parts
  • Parse and format the standard string representation (c232ab00-9414-11ec-b3c8-9f6bdeced846) and the URN representation (urn:uuid:c232ab00-9414-11ec-b3c8-9f6bdeced846)
  • Parse and format the Windows registry form of a GUID — upper case, in braces ({C232AB00-9414-11EC-B3C8-9F6BDECED846}) — as Windows Installer and WiX use it; the hex case and the braces can also be chosen separately
  • Implements format so UUIDs can be printed directly with {f}, and fmt to print them in any of the other forms
  • UUID is a packed union that is exactly 128 bits — compare UUIDs with a.id == b.id, or access the version and variant fields via meta
  • No allocations, no dependencies

Source

The canonical repository is https://git.jcollie.dev/jeff/zig-uuid:

git clone https://git.jcollie.dev/jeff/zig-uuid.git

It is also on the Radicle network, where the repository's identifier is

rad:z3uZSgLiCAhT3BkqgaaoF1SKvye6s

and rad clone rad:z3uZSgLiCAhT3BkqgaaoF1SKvye6s fetches it from any node that seeds it, needing no account and no forge. A further copy is mirrored to https://tangled.org/jcollie.dev/zig-uuid. All three carry the same history on main; the Forgejo one is where the tests and the documentation build run.

Requirements

Zig 0.17.0. The development shell takes the official release binary from zig-overlay.

Installation

Add the dependency to your project:

zig fetch --save git+https://git.jcollie.dev/jeff/zig-uuid

Then in your build.zig:

const uuid = b.dependency("uuid", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("uuid", uuid.module("uuid"));

Examples

Generate a random (version 4) UUID:

const std = @import("std");
const UUID = @import("uuid").UUID;

pub fn main(init: std.process.Init) void {
    const rng_impl: std.Random.IoSource = .{ .io = init.io };
    const rng = rng_impl.interface();

    const uuid: UUID = .new(.{
        .v4 = .{
            .rng = rng,
        },
    });

    std.debug.print("{f}\n", .{uuid});
}

Generate a timestamp-based, sortable (version 7) UUID:

const uuid: UUID = .new(.{
    .v7 = .{
        .unix_ts_ms = .{ .timestamp = .now(io, .real) },
        .rng = rng,
    },
});

Generate a name-based (version 5) UUID. The digest is taken over the name space and then each part of the name in turn, so the result is the same as hashing the parts joined together:

const uuid: UUID = .fromName(.v5, .namespace_dns, &.{"www.example.com"});
// 2ed6657d-e927-568b-95e1-2665a8aea6a2

const component: UUID = .fromName(.v5, my_namespace, &.{ "component/", name });

.v3 uses MD5 instead of SHA-1. If you already have the digest, pass it to UUID.new in the hash field of the .v3 or .v5 options.

Parse and format:

const uuid = try UUID.deserialize("c232ab00-9414-11ec-b3c8-9f6bdeced846");
const str: [36]u8 = uuid.serialize();
const urn: [45]u8 = uuid.serializeUrn();

deserialize also accepts the braced form, in either case, and rejects a brace without its partner. The Windows registry form is available directly, or by choosing the case and the braces yourself:

const guid = try UUID.deserialize("{6BA7B810-9DAD-11D1-80B4-00C04FD430C8}");
const reg: [38]u8 = guid.serializeRegistry(); // {6BA7B810-9DAD-11D1-80B4-00C04FD430C8}
const upper: [36]u8 = guid.serializeOptions(.{ .case = .upper });
std.debug.print("{f}\n", .{guid.fmt(.registry)});

Version 2 (DCE Security) UUIDs store only 28 bits of timestamp and 6 bits of clock sequence, so UUIDs generated within the same ~7 minute window for the same local ID collide easily — prefer another version unless you specifically need DCE semantics.

Standards

The test suite checks against the example values and test vectors from RFC 9562, with the name-based v8 example corrected per erratum 7929.

Development

zig build test   # run the tests
zig build run    # run the example UUID generator
zig build docs   # build the API docs into zig-out/docs
zig build bench  # run the benchmarks (always ReleaseFast)

Contributing

Report issues and send pull requests to the Tangled mirror, https://tangled.org/jcollie.dev/zig-uuid. CONTRIBUTING.md covers setting up, the checks a change has to pass, and how the code is laid out.

License

MIT. This project follows the REUSE specification.