Module: HyperUuid::Runtime
- Defined in:
- lib/hyperuuid/runtime.rb,
lib/hyperuuid/wasm_runtime.rb
Overview
The WebAssembly backend: the same Rust core, compiled once to a wasm32-wasip1 module
(lib/hyperuuid/native/wasm32-wasip1/hyperuuid.wasm) and run inside this process by the
wasmtime gem — no per-platform shared library needed, and nothing dlopen'd. This is the
inverse of ruby.wasm: not Ruby running inside a wasm sandbox, but a wasm module running
inside Ruby.
Same integration shape as the Magnus extension: on require (after runtime.rb has defined
the Fiddle backend) this redefines the HyperUuid::Runtime singleton methods in place
— no delegation layer, no second surface. Everything above Runtime (the Uuid class, the
module doors, batch slicing) stays shared byte-for-byte across all three backends, and the
same Runtime::RandomSourceError / Runtime::TimestampOutOfRangeError classes carry the
same messages.
Two things differ from the native backends, both forced by the sandbox:
- A wasm guest only sees its own linear memory, so no Fiddle::Pointer can cross. Every
buffer the core writes into is obtained from the module's own exported
malloc (the
wasi-libc allocator Rust's std already uses on this target) and read back with
Memory#read. Using the guest's allocator rather than a host-picked offset is
load-bearing: dlmalloc claims the tail of the initial memory on first use, and a batch
written at a guessed offset was observed corrupted by the guest's next allocation.
- A
Wasmtime::Store is single-threaded, so every call is serialized under one Mutex.
One shared instance per process is also what keeps the core's v7 counter — which lives
inside the instance — monotonic across threads and batches, exactly as the one dlopen'd
library does natively.
Defined Under Namespace
Classes: RandomSourceError, TimestampOutOfRangeError, WasmInstance
Constant Summary
collapse
- NATIVE_DIR =
File.join(__dir__, "native")
- WASM_MODULE_PATH =
File.join(NATIVE_DIR, "wasm32-wasip1", "hyperuuid.wasm")
Class Method Summary
collapse
Class Method Details
.fiddle_library_available? ⇒ Boolean
Whether this platform has a shared library for Fiddle to dlopen at all: a known RID
and the file actually present in this install. Backend selection (hyperuuid.rb)
asks this before falling back to the WebAssembly backend, which needs neither.
.new_v4 ⇒ Object
24
25
26
27
28
29
|
# File 'lib/hyperuuid/runtime.rb', line 24
def new_v4
out = scratch
rc = functions[:new_v4].call(out)
raise RandomSourceError, "uuid_new_v4 failed with code #{rc}" unless rc.zero?
out[0, 16]
end
|
.new_v5(namespace_bytes, name_bytes) ⇒ Object
31
32
33
34
35
36
37
38
39
|
# File 'lib/hyperuuid/runtime.rb', line 31
def new_v5(namespace_bytes, name_bytes)
out = scratch
name = name_bytes.empty? ? nil : name_bytes
rc = functions[:new_v5].call(namespace_bytes, name, name_bytes.bytesize, out)
raise RandomSourceError, "uuid_new_v5 failed with code #{rc}" unless rc.zero?
out[0, 16]
end
|
.new_v6(unix_millis) ⇒ Object
41
42
43
44
45
46
47
48
49
|
# File 'lib/hyperuuid/runtime.rb', line 41
def new_v6(unix_millis)
out = scratch
rc = functions[:new_v6].call(unix_millis, out)
case rc
when 0 then out[0, 16]
when 2 then raise TimestampOutOfRangeError, "unix_millis does not fit the 60-bit v6 timestamp field"
else raise RandomSourceError, "uuid_new_v6 failed with code #{rc}"
end
end
|
.new_v6_batch(count, unix_millis) ⇒ Object
55
56
57
58
59
60
61
62
63
64
|
# File 'lib/hyperuuid/runtime.rb', line 55
def new_v6_batch(count, unix_millis)
return "" if count.zero?
out = Fiddle::Pointer.malloc(count * 16, Fiddle::RUBY_FREE)
rc = functions[:new_v6_batch].call(unix_millis, count, out)
case rc
when 0 then out[0, count * 16]
when 2 then raise TimestampOutOfRangeError, "unix_millis does not fit the 60-bit v6 timestamp field"
else raise RandomSourceError, "uuid_new_v6_batch failed with code #{rc}"
end
end
|
.new_v7(unix_millis) ⇒ Object
66
67
68
69
70
71
72
73
74
|
# File 'lib/hyperuuid/runtime.rb', line 66
def new_v7(unix_millis)
out = scratch
rc = functions[:new_v7].call(unix_millis, out)
case rc
when 0 then out[0, 16]
when 2 then raise TimestampOutOfRangeError, "unix_millis must fit within the RFC 9562 48-bit field"
else raise RandomSourceError, "uuid_new_v7 failed with code #{rc}"
end
end
|
.new_v7_batch(count, unix_millis) ⇒ Object
80
81
82
83
84
85
86
87
88
89
|
# File 'lib/hyperuuid/runtime.rb', line 80
def new_v7_batch(count, unix_millis)
return "" if count.zero?
out = Fiddle::Pointer.malloc(count * 16, Fiddle::RUBY_FREE)
rc = functions[:new_v7_batch].call(unix_millis, count, out)
case rc
when 0 then out[0, count * 16]
when 2 then raise TimestampOutOfRangeError, "unix_millis must fit within the RFC 9562 48-bit field"
else raise RandomSourceError, "uuid_new_v7_batch failed with code #{rc}"
end
end
|
.v6_to_rfc_order(bytes) ⇒ Object
103
104
105
|
# File 'lib/hyperuuid/runtime.rb', line 103
def v6_to_rfc_order(bytes)
rewrite(:v6_to_rfc_order, bytes)
end
|
.v6_to_sql_order(bytes) ⇒ Object
99
100
101
|
# File 'lib/hyperuuid/runtime.rb', line 99
def v6_to_sql_order(bytes)
rewrite(:v6_to_sql_order, bytes)
end
|
.v6_unix_millis(bytes) ⇒ Object
51
52
53
|
# File 'lib/hyperuuid/runtime.rb', line 51
def v6_unix_millis(bytes)
functions[:v6_unix_millis].call(bytes)
end
|
.v7_to_rfc_order(bytes) ⇒ Object
95
96
97
|
# File 'lib/hyperuuid/runtime.rb', line 95
def v7_to_rfc_order(bytes)
rewrite(:v7_to_rfc_order, bytes)
end
|
.v7_to_sql_order(bytes) ⇒ Object
91
92
93
|
# File 'lib/hyperuuid/runtime.rb', line 91
def v7_to_sql_order(bytes)
rewrite(:v7_to_sql_order, bytes)
end
|
.v7_unix_millis(bytes) ⇒ Object
76
77
78
|
# File 'lib/hyperuuid/runtime.rb', line 76
def v7_unix_millis(bytes)
functions[:v7_unix_millis].call(bytes)
end
|