hyperuuid 0.1.0-aarch64-linux → 0.2.0-aarch64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2892b5a876b4e3cad50f46aad3f4a778f89b6d72e4c523b6c711979c6c87ef30
4
- data.tar.gz: 61ca11315cb9a92e2221dfa9a752eb83ce9c8c276b4dcf292bf5ce425c66fc55
3
+ metadata.gz: 44f92576d6f75d47a6711d276468afa53fcb3d7743855f5f2e2ece727506f0d4
4
+ data.tar.gz: 7a7094cd8935b92d47e9b13e7ed6c564f21c0d06a6bc569d4922d47c2a305da5
5
5
  SHA512:
6
- metadata.gz: a8e44ec99f418bf148a9611952c64872d933ca2786a760cbb228cfe118c1635a87d7b13d0c2c491b14d0a7f22d68dad482c0f2ef33e73cc952bd2b7ff66e8eda
7
- data.tar.gz: 59e0a033d956900a43f010765a00a3edd79def7863c29b01e9cfbbe8c45339e72afe4dec9c544db26057359011a76b5cc22ac2a22bcae7f4f51bf0ca4f201c67
6
+ metadata.gz: 668531aaaf63a38bafda71ee55daf8782de3dfc43c663e56dad7f2528e6662ca3935ed5b3302b4b42fb62d0bddaf1f7b8b992cb75c60f356303a72d57c78641e
7
+ data.tar.gz: 6ad655d628c646e4bcd0efd3879f6f56e304c62e958074b3b9c9e179ad1ba898f64261e9eb6114adb0bbaab7c3f14bce0bee069ddccd61fab85d5d01cdea6f7e
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Skunk Werkx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # hyperuuid
2
2
 
3
+ [![CI](https://github.com/SkunkWerkx/HyperUuid/actions/workflows/ci.yml/badge.svg)](https://github.com/SkunkWerkx/HyperUuid/actions/workflows/ci.yml)
4
+ [![RubyGems](https://img.shields.io/gem/v/hyperuuid.svg)](https://rubygems.org/gems/hyperuuid)
5
+
3
6
  **Ruby's own stdlib stops at `SecureRandom.uuid` — random v4, full stop. No v5, no v6, no v7. This gem is the whole RFC, with zero gem dependency beyond `Fiddle` (which ships with every Ruby install) — and it's faster than `SecureRandom.uuid` too.**
4
7
 
5
8
  RFC 9562 UUID v4 (random), v5 (deterministic), v6 and v7 (time-sortable) generation, with
@@ -60,6 +63,21 @@ timestamp capture and one native call, instead of `count` of each.
60
63
 
61
64
  The honest trade-off: this gem `dlopen`s a native library instead of being pure Ruby, so it needs a platform-specific `libhyperuuid.so`/`.dylib`/`.dll` bundled alongside it. If plain v4 randomness is all you need, `SecureRandom.uuid` is simpler and already in stdlib — that's a completely reasonable choice.
62
65
 
66
+ ## Bulk generation into bytes
67
+
68
+ `new_v6_batch_bytes` and `new_v7_batch_bytes` return the batch as one binary `String` of raw RFC 9562-ordered bytes — 16 per UUID — instead of an Array of `Uuid` objects:
69
+
70
+ ```ruby
71
+ bytes = HyperUuid.new_v7_batch_bytes(1000)
72
+ first = bytes[0, 16] # ready for a BINARY(16) bind parameter
73
+ ```
74
+
75
+ **About 15x faster than `new_v7_batch`** for a 1000-UUID batch (24 µs versus 370 µs). The native call is identical — the difference is that `new_v7_batch` then allocates 1000 `Uuid` objects and 1000 String slices on top of it. This hands back the bytes the native core already produced, untouched.
76
+
77
+ The catch, and it inverts the advice: **if you need `Uuid` objects, keep using `new_v7_batch`.** Slicing these bytes into objects yourself just relocates the identical allocations into your own code, and measures no better — sometimes worse. Reach for the byte form only when bytes are the destination: a bind parameter, a wire format, a bulk load.
78
+
79
+ Slice it with `bytes[i * 16, 16]` — which is exactly what `new_v7_batch` does internally.
80
+
63
81
  ## Benchmarks
64
82
 
65
83
  Real numbers, `benchmark-ips` on Ruby 4.0.6, linux-arm64 (`ruby benchmark/uuid_benchmark.rb`) — not claimed, measured. With the Magnus backend (the default wherever the extension loads):
@@ -99,9 +117,69 @@ gem install hyperuuid
99
117
 
100
118
  Published to [RubyGems.org](https://rubygems.org/gems/hyperuuid) as real precompiled
101
119
  "platform gems" — `bundle`/`gem install` auto-selects the matching one for
102
- linux-x64/arm64 or osx-x64/arm64 (the compiled Magnus native extension, `backend: :native`),
103
- falling back automatically to the universal `ruby`-platform gem (pure Fiddle, zero compile,
104
- bundles all 6 platforms' native libs) everywhere else — Windows included, since Magnus
105
- doesn't target it. No extra configuration needed either way.
120
+ linux-x64/arm64, osx-x64/arm64, x64-mingw-ucrt or aarch64-mingw-ucrt (the compiled Magnus
121
+ native extension, `backend: :native`), falling back automatically to the universal
122
+ `ruby`-platform gem (pure Fiddle, zero compile, bundles all 6 platforms' native libs)
123
+ everywhere else. No extra configuration needed either way.
124
+
125
+ Selection has **two** axes here, unlike every other binding in this repo. A Magnus extension
126
+ is bound to one Ruby minor ABI — there's no `abi3` equivalent to collapse the version axis the
127
+ way [the Python binding's](../python/) wheels do — so each platform gem is a "fat" gem
128
+ carrying one compiled extension per supported Ruby, under `lib/hyperuuid/<minor>/`, and picks
129
+ one at `require` time:
130
+
131
+ | Ruby | linux-x64/arm64, osx-x64/arm64, x64-mingw-ucrt, aarch64-mingw-ucrt | anywhere else (musl/Alpine, …) |
132
+ | --- | --- | --- |
133
+ | 4.0 (primary) | Magnus, `backend: :native` | Fiddle |
134
+ | 3.4 (floor, until its EOL 2028-03-31) | Magnus, `backend: :native` | Fiddle |
135
+ | 3.2 / 3.3 | Fiddle | Fiddle |
136
+
137
+ The platform gems declare `required_ruby_version >= 3.4, < 4.1` precisely so RubyGems
138
+ *declines* them outside that range and resolves the universal gem instead — a wrong-ABI
139
+ extension must never be installed in the first place. On Windows it would at least fail to
140
+ load cleanly (the extension imports `<arch>-ucrt-ruby<minor>.dll` by name —
141
+ `x64-ucrt-ruby400.dll` on x64, `aarch64-ucrt-ruby400.dll` on ARM), but Linux extensions
142
+ don't link libruby at all, so one can load successfully against the wrong ABI and misbehave
143
+ later. When 3.4 goes EOL it simply leaves the matrix and its users fall back to Fiddle, which
144
+ is exactly what the fallback is for.
145
+
146
+ An earlier edition of this section said the fallback covered "Windows included, since Magnus
147
+ doesn't target it." That was wrong in both halves. MinGW is the *only* Windows flavour
148
+ `rb-sys` targets — its own `data/toolchains.json` maps `x64-mingw-ucrt` to the
149
+ `x86_64-pc-windows-gnu` Rust target, `supported: true`; the target it has no support for is
150
+ `x86_64-pc-windows-msvc`. And Windows is where the Fiddle fallback cost the most: measured
151
+ on win-x64, Ruby 3.4, the Magnus backend does `new_v4` in 406ns against Fiddle's 2407ns
152
+ (**5.9x**) and `new_v7` in 595ns against 2759ns (**4.6x**) — a far wider gap than any Linux
153
+ or macOS leg shows.
154
+
155
+ Windows-on-ARM is no longer the exception it was. `rb-sys` maps `aarch64-mingw-ucrt` to the
156
+ `aarch64-pc-windows-gnullvm` Rust target (`supported: true`), and RubyInstaller ships an
157
+ `aarch64-mingw-ucrt` build of both ABIs in the table above, so win-arm64 now gets the same fat
158
+ platform gem as every other leg. Measured on real Windows-on-ARM hardware, Ruby 4.0.6, the
159
+ Magnus backend does `new_v4` in 416ns against Fiddle's 2299ns (**5.5x**) and `new_v7` in 621ns
160
+ against 2474ns (**4.0x**) — the same shape the x64 leg shows.
161
+
162
+ What differs from the x64 build follows from `gnullvm` being LLVM-based where
163
+ `x86_64-pc-windows-gnu` is GCC-based. The linker driver is `aarch64-w64-mingw32-clang` from
164
+ MSYS2's CLANGARM64 environment — RubyInstaller's own ARM devkit installs it locally, and
165
+ `ruby/setup-ruby` installs it on `windows-11-arm` — so there is no `link-self-contained=no`
166
+ dance. Two flags are load-bearing:
167
+
168
+ - **`-l static=unwind`.** rustc emits its `-lunwind` in the linker's *dynamic* section, where
169
+ CLANGARM64 offers both `libunwind.a` and `libunwind.dll.a` and lld prefers the latter. Left
170
+ alone, the extension acquires a runtime dependency on `libunwind.dll` — a file no consumer
171
+ of the gem would have.
172
+ - **`BINDGEN_EXTRA_CLANG_ARGS=--target=aarch64-w64-mingw32`.** bindgen hands clang the *Rust*
173
+ target triple when cargo cross-compiles, and clang rejects `aarch64-pc-windows-gnullvm`
174
+ outright (`version 'llvm' in target triple ... is invalid`), then fails behind that on a
175
+ missing `stdalign.h` it never reached its own resource dir to find. `aarch64-w64-mingw32`
176
+ is the same ABI spelled the way clang accepts, exactly as x64 spells its gnu target
177
+ `x86_64-w64-mingw32`.
178
+
179
+ That second one was briefly documented here as *unnecessary*, on the strength of a local
180
+ build where it genuinely was: that build used a `gnullvm` **host** toolchain, so host equals
181
+ target, cargo was not cross-compiling, and bindgen injected no `--target` at all. CI's host is
182
+ MSVC, so it does. A local build says nothing about that step unless its host triple matches
183
+ the runner's.
106
184
 
107
185
  See [the repo root README](../README.md) for the full RFC 9562 coverage table and the state of every other language binding.
@@ -5,7 +5,7 @@ module HyperUuid
5
5
  # C-ABI call, no runtime bridge (the same "no shim" positioning as the Go/Swift bindings'
6
6
  # purego/dlopen approach). Fiddle ships with every Ruby install; it's a plain gem
7
7
  # dependency here (see hyperuuid.gemspec) rather than a third-party one — mirroring Go's
8
- # "no cgo" and Python's ctypes-only stance.
8
+ # "no cgo" and Python's zero-dependency PyO3 wheels.
9
9
  #
10
10
  # Unlike the Go/Swift bindings, which embed their native builds inside a single compiled
11
11
  # archive and must extract to a temp file before dlopen can see a real path, a Ruby gem's
@@ -1,7 +1,8 @@
1
1
  module HyperUuid
2
2
  # A parsed 16-byte RFC 9562 UUID value. Minimal by design — this gem has no runtime
3
3
  # dependency on the `uuid` gem, the same "no extra dependency" positioning as the Go
4
- # binding's purego-only/no-cgo approach and the Python binding's stdlib-ctypes-only one.
4
+ # binding's purego-only/no-cgo approach and the Python binding's dependency-free PyO3
5
+ # wheels.
5
6
  class Uuid
6
7
  include Comparable
7
8
 
data/lib/hyperuuid.rb CHANGED
@@ -13,7 +13,7 @@ require_relative "hyperuuid/runtime"
13
13
  module HyperUuid
14
14
  # This gem's own version — distinct from the RFC 9562 UUID *versions* (v4/v5/v6/v7) the
15
15
  # rest of this module generates.
16
- VERSION = "0.1.0"
16
+ VERSION = "0.2.0"
17
17
 
18
18
  # Creates a random UUID version 4 (RFC 9562 §5.4).
19
19
  def self.new_v4
@@ -78,6 +78,34 @@ module HyperUuid
78
78
  bytes = Runtime.new_v7_batch(count, unix_millis_from(unix_millis))
79
79
  Array.new(count) { |i| Uuid.new(bytes[i * 16, 16]) }
80
80
  end
81
+
82
+ # Returns `count` version 7 UUIDs as one binary String of raw RFC 9562-ordered bytes,
83
+ # 16 per UUID, instead of an Array of Uuid objects.
84
+ #
85
+ # Roughly 11x faster than #new_v7_batch for a 1000-UUID batch (about 35 us versus 400 us).
86
+ # The difference is not the native call — that is identical — it is that #new_v7_batch then
87
+ # allocates `count` Uuid objects and `count` String slices on top of it. This hands back the
88
+ # bytes the native core already produced, untouched.
89
+ #
90
+ # Use it when bytes are the destination: a BYTEA/uniqueidentifier bind parameter, a wire
91
+ # format, a bulk COPY. If you need Uuid objects, keep using #new_v7_batch — slicing this
92
+ # String into them yourself just moves the same allocations into your own code.
93
+ #
94
+ # Slice it with `bytes[i * 16, 16]`, which is what #new_v7_batch does internally.
95
+ def self.new_v7_batch_bytes(count, unix_millis = nil)
96
+ Runtime.new_v7_batch(count, unix_millis_from(unix_millis))
97
+ end
98
+
99
+ # Returns `count` version 6 UUIDs as one binary String of raw RFC 9562-ordered bytes,
100
+ # 16 per UUID. The version 6 counterpart to #new_v7_batch_bytes, with the same rationale and
101
+ # the same guidance about when it is the right call.
102
+ #
103
+ # clock_seq and node are independently random per item; unlike version 7 there is no
104
+ # monotonic counter, so items minted in the same millisecond are not guaranteed to sort in
105
+ # creation order.
106
+ def self.new_v6_batch_bytes(count, unix_millis = nil)
107
+ Runtime.new_v6_batch(count, unix_millis_from(unix_millis))
108
+ end
81
109
  end
82
110
 
83
111
  # --- backend selection: the Magnus extension, when present, replaces the Runtime methods
@@ -91,10 +119,24 @@ HyperUuid::BACKEND =
91
119
  if ENV["HYPERUUID_PURE"]
92
120
  :fiddle
93
121
  else
122
+ # Two layouts, and both have to work. A released platform gem is a "fat" gem carrying one
123
+ # extension per supported Ruby ABI under lib/hyperuuid/<minor>/ (see the Rakefile's
124
+ # native:gem task for why an ABI-per-file is unavoidable — Magnus has no `abi3`
125
+ # equivalent). CI's in-job staging and a local `cargo build --release --features ruby`
126
+ # instead drop a single extension flat at lib/. Trying the versioned path first and the
127
+ # flat one second means neither has to know the other exists.
128
+ #
129
+ # A miss on both is not an error: it means this Ruby/platform combination has no
130
+ # precompiled extension, which is precisely what the Fiddle backend below is for.
94
131
  begin
95
- require "hyperuuid_native"
132
+ require "hyperuuid/#{RUBY_VERSION[/\d+\.\d+/]}/hyperuuid_native"
96
133
  :native
97
134
  rescue LoadError
98
- :fiddle
135
+ begin
136
+ require "hyperuuid_native"
137
+ :native
138
+ rescue LoadError
139
+ :fiddle
140
+ end
99
141
  end
100
142
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyperuuid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Brian Buvinghausen
@@ -73,8 +73,11 @@ executables: []
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
+ - LICENSE
76
77
  - README.md
77
78
  - lib/hyperuuid.rb
79
+ - lib/hyperuuid/3.4/hyperuuid_native.so
80
+ - lib/hyperuuid/4.0/hyperuuid_native.so
78
81
  - lib/hyperuuid/namespaces.rb
79
82
  - lib/hyperuuid/native/README.md
80
83
  - lib/hyperuuid/native/linux-arm64/libhyperuuid.so
@@ -86,7 +89,6 @@ files:
86
89
  - lib/hyperuuid/native_platform.rb
87
90
  - lib/hyperuuid/runtime.rb
88
91
  - lib/hyperuuid/uuid.rb
89
- - lib/hyperuuid_native.so
90
92
  homepage: https://github.com/SkunkWerkx/HyperUuid
91
93
  licenses:
92
94
  - MIT
@@ -99,14 +101,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
101
  requirements:
100
102
  - - ">="
101
103
  - !ruby/object:Gem::Version
102
- version: '3.2'
104
+ version: '3.4'
105
+ - - "<"
106
+ - !ruby/object:Gem::Version
107
+ version: '4.1'
103
108
  required_rubygems_version: !ruby/object:Gem::Requirement
104
109
  requirements:
105
110
  - - ">="
106
111
  - !ruby/object:Gem::Version
107
112
  version: '0'
108
113
  requirements: []
109
- rubygems_version: 3.6.9
114
+ rubygems_version: 4.0.16
110
115
  specification_version: 4
111
116
  summary: RFC 9562 UUID v4/v5/v6/v7 generation — direct native FFI into a Rust core,
112
117
  no runtime bridge.
Binary file