Repository navigation
v0.1.1 - Now genuinely no_std and allocation-free
The Rust core is now genuinely no_std and allocation-free — the no-std category it has
published since v0.1.0 is compiler-enforced instead of asserted, and it no longer links alloc
either. The other seven bindings keep the same API and behavior; they pick up packaging and
documentation fixes and are rebuilt against the new core.
hyperuuid (crates.io)
The crate is #![no_std] under default-features = false
v0.1.0 shipped categories = ["data-structures", "no-std"] while the library still required
std in four places — a claim that was live and false on crates.io. It's now true and the
compiler holds it:
[dependencies]
hyperuuid = { version = "0.1.1", default-features = false }std is a new default-on feature rather than an unconditional #![no_std], because this crate
also builds the cdylib every other binding in this repo dlopens, and a linked artifact needs a
#[panic_handler] that only std supplies. The shared library builds exactly as before.
What moved off std:
NewV6Error/NewV7Errorimplementcore::error::Error(the same trait —std::error::Error
is a re-export of it, so nothing changes for existing callers).getrandom's std-only error impl now rides thestdfeature instead of being pinned on
unconditionally, so it's no longer forced into every consumer's graph.v7::now_v7is compiled out withoutstd, joining thewasm32gate it already had. It is the
only API that reads a system clock; everything else in the crate is timestamp-in, bytes-out.v7's monotonic counter replacedstd::sync::OnceLockwith a lock-free seed fold over
core::sync::atomic. The seed is added rather than stored, so it commutes with concurrent
increments instead of clobbering one — the RFC 9562 §6.2 ordering guarantee is unchanged.
No allocator required either
new_v6_batch/new_v7_batch were the crate's only allocation: a count-sized scratch buffer for
their single getrandom call. That buffer is gone. The batch's entropy is now drawn into the front
of the caller's own output buffer and moved out to each item's octets as the batch is written
backwards, so there is no scratch space at all — not on the heap, and not a fixed stack frame
either, which would have been a poor thing to charge a microcontroller for.
The crate no longer contains extern crate alloc, so it now also carries the
no-std::no-alloc category. Benchmarked against the previous implementation on the same machine:
v7 batch slightly faster (one less alloc/free), v6 within noise. The published batch speedups
(2.5x v6, 3.6x v7 over an equivalent loop) still hold.
Upgrading
For essentially everyone this is a drop-in patch release: default features are on, and the public
API is byte-for-byte identical.
One exception. If your Cargo.toml already said default-features = false, that line was
inert in v0.1.0 — the crate had no default features, so you got a full std build regardless. On
v0.1.1 it now means what it says, and v7::now_v7 will disappear. Either drop the line, or take
the no_std path deliberately, which additionally needs:
- an entropy backend — off std there's no OS for
getrandomto read from, so build with
RUSTFLAGS='--cfg getrandom_backend="custom"'and export a__getrandom_v03_customsymbol; - your own timestamps — pass them to
v7::new_v7/v6::new_v6in place ofnow_v7.
Also worth knowing: the batch functions draw their entropy before assembling any UUID, so on
NewV6Error::Random/NewV7Error::Random no UUID has been written, but the front of out may hold
partial bytes from the failed draw. Previously out was left untouched on that path. Treat the
buffer as clobbered rather than intact when a batch call returns Err.
C#, Java, Go, Python, Ruby, PHP, Swift
No API change and no behavior change: each binding calls the same C ABI, which is untouched — all
12 exported symbols are identical. They're rebuilt against the new core and republished so the
version stays coordinated across all eight registries.
Two things did change for these packages:
- LICENSE and README now ship inside the package on NuGet, Maven, PyPI and RubyGems, rather
than the license only being named in metadata. Nothing to do on your side; it's there if your
build or compliance tooling looks for the actual text. - Documentation corrections — references to the retired ctypes backend are gone, each
binding's README is now about that binding rather than the repo at large, and all of them carry
CI and registry badges.
Install
Same eight packages, same coordinated version — see the
v0.1.0 notes for the full install
table. As before, Go's module needs its own go/v0.1.1 tag pushed alongside this one, since a
subdirectory module can't be resolved from the bare tag.
Verification
Everything above was measured or compiled, not argued:
cargo check --no-default-features --target thumbv7em-none-eabi— clean against a real
bare-metal target. Added to CI as acheck-no-stdjob, because every other cargo invocation in
the pipeline compiles the std configuration and would never notice ause std::creeping back.cargo build --no-default-featureson the host now fails with two errors, not three: "no global
memory allocator found" is gone, which is the direct proofallocis unlinked.tests/allocation_free.rswraps a counting#[global_allocator]around v4/v5/v6/v7 and both
batch functions, asserting zero allocations for all of them — the batch exception it used to
assert is gone.- New
v7_batch_trailing_entropy_is_distinct_per_item(and its v6 counterpart) pin the in-place
entropy placement. Reversing the backwards walk fails them immediately; every other v7 batch test
still passes, because the monotonic counter keeps values ordered even when the entropy is wrecked. - New
tests/v7_counter_race.rsruns 8 threads x 5,000 same-millisecond calls in a fresh process,
covering the counter's first concurrent calls while the seed is still landing. - 54 unit tests + 2 integration tests green; Go, C# (39), Java (38), Swift (37), PHP (46), Ruby (49,
run twice for both the Magnus and Fiddle backends) and Python (46) all green against a freshly
built native.