Repository navigation
v0.4.0 - Alpine, a linked-in core, and every benchmark re-measured
0.4.0 widens where HyperUuid runs, removes the shared library from the builds that never needed one, and replaces the published benchmarks with a fresh set measured on x86-64. The full list is in CHANGELOG.md.
Highlights
- Alpine works.
linux-musl-x64andlinux-musl-arm64are built, attested and shipped in every package (asmusllinux_1_2wheels for Python). Through 0.3.0 Alpine got the glibc library, which does not load under musl. - The core links in where it can.
- Swift on Linux links a static library through SwiftPM, which adds the static Linux SDK (musl) and WebAssembly to that binding. Nothing has to be deployed beside the executable.
- Go cgo builds on Linux and macOS link the core instead of embedding and
dlopening it. The binary starts without touching the filesystem and runs from a read-only orscratchimage. - C# Native AOT publishes link the core into the executable.
- A load probe in every binding. The core reports its own version (
hyperuuid_version), and each binding fronts it with a check that never throws:UuidGenerator.IsAvailable/NativeVersionin C#, and the same pair in each language's idiom. - Java in a GraalVM Native Image is fast. FFM calls were being interpreted there: 6.4 µs per
newV7(long)against 36 ns on the JVM. They are now compiled: 78 ns. Nothing changes on the JVM, and a consumer'snative-imagebuild needs no configuration. - Python and Ruby calls cost about half.
- Python:
new_v4()540 → 243 ns,new_v7(ms)726 → 354 ns,v7_timestamp466 → 252 ns. Wheels are unchanged (still oneabi3wheel per platform). - Ruby:
new_v4317 → 234 ns,new_v7512 → 284 ns on the Magnus backend.
- Python:
- New in Python:
v6_unix_millisandv7_unix_millisreturn the embedded timestamp as anint, with nodatetimebuilt (161 ns). The package is now typed (py.typed).
Benchmarks, re-measured
Every table was re-measured on linux-x64 (Intel Core i9-11900H) with each binding's own harness. The previous figures came from an arm64 WSL2 machine whose slow clock read inflated several ratios, so some headline numbers are smaller than in 0.3.0. Each README names the machine and runtime behind its tables.
| Binding | Generation vs. the platform's own call |
|---|---|
| Swift | 9.5–13x faster than Foundation.UUID() |
| C# | 5.7–8.1x faster than Guid.NewGuid() |
| Ruby | 2.1–4.9x faster than SecureRandom.uuid |
| Python | 3.0–4.2x faster than stdlib uuid |
| Java | 2.4–4.5x faster than UUID.randomUUID() |
| Rust | 2x faster than the uuid crate on v5/v7, level on v4/v6 |
| PHP | level to 1.2x faster than a naive inline v4 |
| Go | slower per call than google/uuid; use the batch doors |
Upgrade notes
Runtime floors. Every floor that had reached end of life is raised. A consumer on an older runtime keeps resolving 0.3.0.
| Floor | |
|---|---|
| Python | 3.11 |
| Ruby | 3.3 |
| PHP | 8.2 |
| Java | JDK 25 |
| Swift | 6.2 |
Behaviour changes.
- Ruby, PHP:
Uuid.parseaccepts the 8-4-4-4-12 form only. Bare and misplaced-hyphen strings no longer parse. - Python: a
datetimepassed tonew_v6/new_v7is truncated to its millisecond. It used to be rounded and could stamp a UUID up to half a millisecond late. - Every binding: caller errors (out-of-range timestamps and counts, wrong types, null names) are now the same exception on every backend and name the mistake. Ruby's are
HyperUuid::TimestampOutOfRangeErrorandRandomSourceError; theRuntime::names remain as aliases. - Go: batch functions return
ErrNegativeCountfor a negative count.-tags hyperuuid_dynamickeeps the previous loading cgo backend. - C#: set
HyperUuidStaticLink=falseto keep the shared library under Native AOT. Blazor WebAssembly requires .NET 11; an older browser project gets warningHYPERUUID001and no native link. - Java: the optional GraalWasm engine moves to 25.4.4.1.1. It must be the same release as the GraalVM JDK you run on.
- Unknown architectures are no longer treated as x64. Go and PHP report an unsupported platform, Swift refuses to compile, and Java falls back to its wasm backend.
- Intel macOS (
osx-x64) still ships in every package. There is no precompiledx86_64-darwingem; Ruby there runs on the Fiddle backend.
Fixes
- An empty v5 name crossed the C ABI as a null pointer from C#, Go, Ruby (Fiddle) and Swift, which the core then built a slice from. Fixed in the core; every binding pins the empty-name vector.
- Java: a batch count past
Integer.MAX_VALUE / 16wrote past a Java array. It is nowIllegalArgumentException. - Python:
new_v6_batch/new_v7_batchnarrowedcountto 32 bits, so2**32 + 1returned one UUID. Out of range is nowValueError. - Swift:
newV6(_: Date)/newV7(_: Date)trapped on a date before 1970, and a missing resource bundle crashed the process. Both are thrown errors now. - Go: a core missing a symbol panicked on the purego backend.
- Ruby: on Alpine, 0.3.0 loaded the glibc library and the first call raised
Fiddle::DLError. - C#: a Blazor WebAssembly app could not use HyperUuid and HyperCast together (duplicate symbol at link time), failed in the browser on .NET 11, and got no native link when it reached the package through a class library.
Verifying
Every native library and static archive in this release is built by CI and carries a build-provenance attestation:
gh attestation verify go/native/linux-x64/libhyperuuid.so \
--repo SkunkWerkx/HyperUuid --signer-repo SkunkWerkx/.github