Proposal: UUID library (Uuid.*) — v4 random + v7 time-ordered IDs for multiplayer, saves, mods #16

Closed
opened 2026-08-29 20:21:59 +02:00 by orkun · 1 comment
Owner

Summary

A tiny built-in UUID library — generate and parse universally-unique
identifiers (v4 random, and v7 time-ordered) — for stable IDs that don't collide.

Why it matters for game devs

  • Multiplayer: identify players, sessions, and networked entities without a
    central authority handing out numbers.
  • Saves & mods: stable IDs for user-created content (levels, items) that
    survive merges and sharing.
  • Analytics / bug reports: a per-install or per-run ID.

Proposed API (illustrative)

# doc-check: skip — illustrative API sketch
let id = Uuid.new()               # v4 random
let k  = Uuid.new_v7()            # time-ordered (sorts by creation, DB-friendly)
Text.from(Uuid.to_text(id))       # "550e8400-e29b-41d4-a716-446655440000"
let p  = try Uuid.parse(s) else return   # validate untrusted input
Uuid.equals(a, b)
  • new (v4), new_v7 (time-ordered), parse, to_text, equals, nil.
  • 128-bit value type; cheap to copy and compare.

Considerations

  • Randomness source: use a proper OS CSPRNG for v4 — but keep it OUT of the
    deterministic simulation RNG (IDs are non-deterministic input; document this so
    people don't break replays/lockstep by minting UUIDs in gameplay).
  • v7 needs the Time library for its timestamp component.
  • Native/C-free; small, no external deps.
  • Fixed-size stack value, not a heap string, for perf.

Scope / acceptance

  • 128-bit UUID type + v4 and v7 generation.
  • parse/to_text/equals/nil, with parse returning an error value.
  • Docs page noting the determinism caveat.
  • Tests (format round-trip, version/variant bits, v7 ordering).

Related: Time, Crypto/RNG, error handling, networking proposals.

## Summary A tiny built-in **UUID** library — generate and parse universally-unique identifiers (v4 random, and v7 time-ordered) — for stable IDs that don't collide. ## Why it matters for game devs - **Multiplayer**: identify players, sessions, and networked entities without a central authority handing out numbers. - **Saves & mods**: stable IDs for user-created content (levels, items) that survive merges and sharing. - **Analytics / bug reports**: a per-install or per-run ID. ## Proposed API (illustrative) ```ludic # doc-check: skip — illustrative API sketch let id = Uuid.new() # v4 random let k = Uuid.new_v7() # time-ordered (sorts by creation, DB-friendly) Text.from(Uuid.to_text(id)) # "550e8400-e29b-41d4-a716-446655440000" let p = try Uuid.parse(s) else return # validate untrusted input Uuid.equals(a, b) ``` - `new` (v4), `new_v7` (time-ordered), `parse`, `to_text`, `equals`, `nil`. - 128-bit value type; cheap to copy and compare. ## Considerations - **Randomness source**: use a proper OS CSPRNG for v4 — but keep it OUT of the deterministic simulation RNG (IDs are non-deterministic input; document this so people don't break replays/lockstep by minting UUIDs in gameplay). - v7 needs the Time library for its timestamp component. - Native/C-free; small, no external deps. - Fixed-size stack value, not a heap string, for perf. ## Scope / acceptance - [ ] 128-bit UUID type + v4 and v7 generation. - [ ] `parse`/`to_text`/`equals`/`nil`, with parse returning an error value. - [ ] Docs page noting the determinism caveat. - [ ] Tests (format round-trip, version/variant bits, v7 ordering). Related: Time, Crypto/RNG, error handling, networking proposals.
orkun added the
proposal
priority:medium
area:stdlib
labels 2026-08-29 20:21:59 +02:00
Author
Owner

Done in commit 2ddf830.

Added the Uuid.* namespace:

  • v4 (Uuid.new / Uuid.v4) — 122 random bits from the OS CSPRNG.
  • v7 (Uuid.new_v7 / Uuid.v7) — 48-bit Unix-ms timestamp prefix + random tail, so IDs sort by creation time; version/variant bits set per RFC 4122.
  • Uuid.parse (normalises untrusted input to lowercase, or the nil UUID), Uuid.is_valid, Uuid.to_text, Uuid.equals (case-insensitive), Uuid.nil.

Represented as the canonical lowercase 36-char string (the form you store/print/send/compare), reusing the crypto prelude's CSPRNG + hex encoder. The determinism caveat is documented: v4 and v7's random tail are non-deterministic, so mint IDs at the edges, never inside lockstep simulation.

Acceptance:

  • 128-bit UUID value + v4 and v7 generation (as canonical text; a packed 128-bit value type is a possible future optimisation)
  • parse/to_text/equals/nil — parse folds invalid input to nil; pair with is_valid to reject
  • Docs page noting the determinism caveat
  • Tests (format round-trip, version/variant bits, validation, parse/equals)

Tests: examples/library/uuid.ludic (wired into x test). Docs: new docs/language/uuid/ section.

Note on error handling: the sketch's try Uuid.parse(s) else ... awaits the error-handling proposal (#8); until then parse returns nil on bad input and is_valid is the explicit reject path.

Done in commit `2ddf830`. Added the `Uuid.*` namespace: - **v4** (`Uuid.new` / `Uuid.v4`) — 122 random bits from the OS CSPRNG. - **v7** (`Uuid.new_v7` / `Uuid.v7`) — 48-bit Unix-ms timestamp prefix + random tail, so IDs sort by creation time; version/variant bits set per RFC 4122. - `Uuid.parse` (normalises untrusted input to lowercase, or the nil UUID), `Uuid.is_valid`, `Uuid.to_text`, `Uuid.equals` (case-insensitive), `Uuid.nil`. Represented as the canonical lowercase 36-char string (the form you store/print/send/compare), reusing the crypto prelude's CSPRNG + hex encoder. The determinism caveat is documented: v4 and v7's random tail are non-deterministic, so mint IDs at the edges, never inside lockstep simulation. **Acceptance:** - [x] 128-bit UUID value + v4 and v7 generation (as canonical text; a packed 128-bit value type is a possible future optimisation) - [x] `parse`/`to_text`/`equals`/`nil` — parse folds invalid input to nil; pair with `is_valid` to reject - [x] Docs page noting the determinism caveat - [x] Tests (format round-trip, version/variant bits, validation, parse/equals) Tests: `examples/library/uuid.ludic` (wired into `x test`). Docs: new `docs/language/uuid/` section. Note on error handling: the sketch's `try Uuid.parse(s) else ...` awaits the error-handling proposal (#8); until then `parse` returns nil on bad input and `is_valid` is the explicit reject path.
orkun closed this issue 2026-08-30 20:58:41 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: workshopsoft/ludic#16
No description provided.