goldenanalysis-native 0.1.0__tar.gz

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.
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: goldenanalysis-native
3
+ Version: 0.1.0
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: 3 :: Only
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: Topic :: Scientific/Engineering
9
+ Summary: Optional native (Rust/PyO3) acceleration kernels for goldenanalysis
10
+ Author-email: Ben Severn <ben@bensevern.dev>
11
+ License: MIT
12
+ Requires-Python: >=3.11
13
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
14
+ Project-URL: Homepage, https://github.com/benseverndev-oss/goldenmatch
15
+
16
+ # goldenanalysis-native
17
+
18
+ Optional native (Rust/PyO3) acceleration kernels for
19
+ [`goldenanalysis`](https://github.com/benseverndev-oss/goldenmatch/tree/main/packages/python/goldenanalysis).
20
+
21
+ You don't import this directly. `goldenanalysis` stays a pure-Python wheel;
22
+ `pip install goldenanalysis[native]` pulls this compiled abi3 wheel, and
23
+ `goldenanalysis.core._native_loader` discovers it (falling back to the pure-Python
24
+ path when it isn't present).
25
+
26
+ The kernel mirrors the pure-Python aggregation loops in
27
+ `goldenanalysis/core/aggregate.py` (`histogram`, `quantile`) value-for-value, reading
28
+ input as a Float64 Arrow array (zero-copy, C Data Interface). A primitive is only
29
+ used under `GOLDENANALYSIS_NATIVE=auto` once it has cleared
30
+ `_native_loader._GATED_ON` — proven byte-identical **and** measured to move the wall
31
+ on a real shape. The two-crate split (pyo3-free `analysis-core` + this abi3 shim)
32
+ mirrors `goldencheck-core`/`goldencheck-native`.
33
+
34
+ Build in-tree for local dev (drops `goldenanalysis/_native.abi3.so`):
35
+
36
+ ```bash
37
+ uv run python scripts/build_analysis_native.py
38
+ ```
39
+
40
+ MIT.
41
+
@@ -0,0 +1,25 @@
1
+ # goldenanalysis-native
2
+
3
+ Optional native (Rust/PyO3) acceleration kernels for
4
+ [`goldenanalysis`](https://github.com/benseverndev-oss/goldenmatch/tree/main/packages/python/goldenanalysis).
5
+
6
+ You don't import this directly. `goldenanalysis` stays a pure-Python wheel;
7
+ `pip install goldenanalysis[native]` pulls this compiled abi3 wheel, and
8
+ `goldenanalysis.core._native_loader` discovers it (falling back to the pure-Python
9
+ path when it isn't present).
10
+
11
+ The kernel mirrors the pure-Python aggregation loops in
12
+ `goldenanalysis/core/aggregate.py` (`histogram`, `quantile`) value-for-value, reading
13
+ input as a Float64 Arrow array (zero-copy, C Data Interface). A primitive is only
14
+ used under `GOLDENANALYSIS_NATIVE=auto` once it has cleared
15
+ `_native_loader._GATED_ON` — proven byte-identical **and** measured to move the wall
16
+ on a real shape. The two-crate split (pyo3-free `analysis-core` + this abi3 shim)
17
+ mirrors `goldencheck-core`/`goldencheck-native`.
18
+
19
+ Build in-tree for local dev (drops `goldenanalysis/_native.abi3.so`):
20
+
21
+ ```bash
22
+ uv run python scripts/build_analysis_native.py
23
+ ```
24
+
25
+ MIT.
@@ -0,0 +1,7 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "analysis-core"
7
+ version = "0.1.0"
@@ -0,0 +1,21 @@
1
+ # analysis-core -- pyo3-free aggregation kernels for GoldenAnalysis. The byte-
2
+ # identical Rust mirror of goldenanalysis/core/aggregate.py's pure-Python
3
+ # histogram + quantile loops. The pyo3 + Arrow C Data Interface shims live in the
4
+ # sibling `analysis-native` crate, which path-depends on this one. Keeping the
5
+ # kernel pyo3-free means it can later back a DataFusion/DuckDB SQL surface (as
6
+ # `score-core`/`graph-core` do for goldenmatch) without dragging in CPython.
7
+ # Excluded from the bridge workspace (packages/rust/extensions/Cargo.toml).
8
+ [package]
9
+ name = "analysis-core"
10
+ version = "0.1.0"
11
+ edition = "2021"
12
+ license = "MIT"
13
+ authors = ["Ben Severn <ben@bensevern.dev>"]
14
+ description = "Pyo3-free aggregation kernels for GoldenAnalysis (histogram, quantile)"
15
+
16
+ [lib]
17
+ name = "analysis_core"
18
+
19
+ [profile.release]
20
+ opt-level = 3
21
+ lto = "thin"
@@ -0,0 +1,118 @@
1
+ //! Pyo3-free aggregation kernels for GoldenAnalysis.
2
+ //!
3
+ //! Byte-identical Rust mirror of the pure-Python loops in
4
+ //! `goldenanalysis/core/aggregate.py` (`histogram`, `quantile`). The pure-Python
5
+ //! path stays the reference + fallback; these kernels back the optional
6
+ //! `analysis-native` abi3 wheel. No pyo3, no Arrow -- plain slices in, plain
7
+ //! values out -- so the same logic can later back a SQL surface.
8
+ //!
9
+ //! Inputs are assumed finite (cluster sizes / scores). NaN/inf are out of the
10
+ //! parity contract: the Python reference (`min`/`max`/`sorted`) is undefined on
11
+ //! them too.
12
+
13
+ /// Equal-width histogram over `[min, max]`, mirroring `aggregate.histogram`.
14
+ ///
15
+ /// Returns `[(left_edge, count), ...]` with `bins` entries; the right edge is
16
+ /// inclusive (the max lands in the last bin); all-equal input collapses to a
17
+ /// single `[(value, count)]` bin; empty input or `bins < 1` => `[]`. Uses the
18
+ /// SAME float op order as the Python loop so the edges + bucket assignment are
19
+ /// bit-identical.
20
+ pub fn histogram(values: &[f64], bins: i64) -> Vec<(f64, i64)> {
21
+ if values.is_empty() || bins < 1 {
22
+ return Vec::new();
23
+ }
24
+ let bins = bins as usize;
25
+ let mut lo = values[0];
26
+ let mut hi = values[0];
27
+ for &v in values {
28
+ if v < lo {
29
+ lo = v;
30
+ }
31
+ if v > hi {
32
+ hi = v;
33
+ }
34
+ }
35
+ if hi == lo {
36
+ return vec![(lo, values.len() as i64)];
37
+ }
38
+ let width = (hi - lo) / bins as f64;
39
+ let mut counts = vec![0i64; bins];
40
+ for &v in values {
41
+ // int((v - lo) / width): truncates toward zero == Python int() for >= 0.
42
+ let mut idx = ((v - lo) / width) as usize;
43
+ if idx >= bins {
44
+ idx = bins - 1; // right-edge inclusive
45
+ }
46
+ counts[idx] += 1;
47
+ }
48
+ (0..bins).map(|i| (lo + i as f64 * width, counts[i])).collect()
49
+ }
50
+
51
+ /// Linear-interpolation quantile (numpy default), mirroring `aggregate.quantile`.
52
+ ///
53
+ /// Empty input => `0.0`. Single value => that value. Otherwise interpolates
54
+ /// between the two order statistics straddling `q*(n-1)`, the same op order as
55
+ /// the Python loop. Inputs assumed finite.
56
+ pub fn quantile(values: &[f64], q: f64) -> f64 {
57
+ if values.is_empty() {
58
+ return 0.0;
59
+ }
60
+ let mut vals = values.to_vec();
61
+ vals.sort_by(|a, b| a.total_cmp(b));
62
+ if vals.len() == 1 {
63
+ return vals[0];
64
+ }
65
+ let pos = q * (vals.len() - 1) as f64;
66
+ let lo_idx = pos as usize; // int(pos); pos >= 0 for q in [0, 1]
67
+ let frac = pos - lo_idx as f64;
68
+ if lo_idx + 1 < vals.len() {
69
+ vals[lo_idx] + (vals[lo_idx + 1] - vals[lo_idx]) * frac
70
+ } else {
71
+ vals[lo_idx]
72
+ }
73
+ }
74
+
75
+ #[cfg(test)]
76
+ mod tests {
77
+ use super::*;
78
+
79
+ #[test]
80
+ fn histogram_empty_or_no_bins() {
81
+ assert_eq!(histogram(&[], 10), Vec::new());
82
+ assert_eq!(histogram(&[1.0, 2.0], 0), Vec::new());
83
+ assert_eq!(histogram(&[1.0, 2.0], -1), Vec::new());
84
+ }
85
+
86
+ #[test]
87
+ fn histogram_all_equal_collapses() {
88
+ assert_eq!(histogram(&[5.0], 3), vec![(5.0, 1)]);
89
+ assert_eq!(histogram(&[2.0, 2.0, 2.0], 4), vec![(2.0, 3)]);
90
+ }
91
+
92
+ #[test]
93
+ fn histogram_right_edge_inclusive() {
94
+ // 0..=10 over 10 bins (width 1): the max (10) lands in the last bin with 9.
95
+ let vals: Vec<f64> = (0..=10).map(|i| i as f64).collect();
96
+ let got = histogram(&vals, 10);
97
+ let expected: Vec<(f64, i64)> = (0..10)
98
+ .map(|i| (i as f64, if i == 9 { 2 } else { 1 }))
99
+ .collect();
100
+ assert_eq!(got, expected);
101
+ }
102
+
103
+ #[test]
104
+ fn quantile_edges_and_interpolation() {
105
+ // cluster sizes [1, 1, 3, 2] -> sorted [1, 1, 2, 3]
106
+ let sizes = [1.0, 1.0, 3.0, 2.0];
107
+ assert_eq!(quantile(&sizes, 0.5), 1.5); // 1 + (2-1)*0.5
108
+ assert!((quantile(&sizes, 0.95) - 2.85).abs() < 1e-12); // 2 + (3-2)*0.85
109
+ assert_eq!(quantile(&sizes, 0.0), 1.0); // min
110
+ assert_eq!(quantile(&sizes, 1.0), 3.0); // max
111
+ }
112
+
113
+ #[test]
114
+ fn quantile_empty_and_single() {
115
+ assert_eq!(quantile(&[], 0.5), 0.0);
116
+ assert_eq!(quantile(&[7.0], 0.5), 7.0);
117
+ }
118
+ }
@@ -0,0 +1,949 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "ahash"
7
+ version = "0.8.12"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
10
+ dependencies = [
11
+ "cfg-if",
12
+ "const-random",
13
+ "getrandom 0.3.4",
14
+ "once_cell",
15
+ "version_check",
16
+ "zerocopy",
17
+ ]
18
+
19
+ [[package]]
20
+ name = "aho-corasick"
21
+ version = "1.1.4"
22
+ source = "registry+https://github.com/rust-lang/crates.io-index"
23
+ checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
24
+ dependencies = [
25
+ "memchr",
26
+ ]
27
+
28
+ [[package]]
29
+ name = "analysis-core"
30
+ version = "0.1.0"
31
+
32
+ [[package]]
33
+ name = "analysis-native"
34
+ version = "0.1.0"
35
+ dependencies = [
36
+ "analysis-core",
37
+ "arrow",
38
+ "pyo3",
39
+ ]
40
+
41
+ [[package]]
42
+ name = "android_system_properties"
43
+ version = "0.1.5"
44
+ source = "registry+https://github.com/rust-lang/crates.io-index"
45
+ checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
46
+ dependencies = [
47
+ "libc",
48
+ ]
49
+
50
+ [[package]]
51
+ name = "arrow"
52
+ version = "55.2.0"
53
+ source = "registry+https://github.com/rust-lang/crates.io-index"
54
+ checksum = "f3f15b4c6b148206ff3a2b35002e08929c2462467b62b9c02036d9c34f9ef994"
55
+ dependencies = [
56
+ "arrow-arith",
57
+ "arrow-array",
58
+ "arrow-buffer",
59
+ "arrow-cast",
60
+ "arrow-data",
61
+ "arrow-ord",
62
+ "arrow-pyarrow",
63
+ "arrow-row",
64
+ "arrow-schema",
65
+ "arrow-select",
66
+ "arrow-string",
67
+ ]
68
+
69
+ [[package]]
70
+ name = "arrow-arith"
71
+ version = "55.2.0"
72
+ source = "registry+https://github.com/rust-lang/crates.io-index"
73
+ checksum = "30feb679425110209ae35c3fbf82404a39a4c0436bb3ec36164d8bffed2a4ce4"
74
+ dependencies = [
75
+ "arrow-array",
76
+ "arrow-buffer",
77
+ "arrow-data",
78
+ "arrow-schema",
79
+ "chrono",
80
+ "num",
81
+ ]
82
+
83
+ [[package]]
84
+ name = "arrow-array"
85
+ version = "55.2.0"
86
+ source = "registry+https://github.com/rust-lang/crates.io-index"
87
+ checksum = "70732f04d285d49054a48b72c54f791bb3424abae92d27aafdf776c98af161c8"
88
+ dependencies = [
89
+ "ahash",
90
+ "arrow-buffer",
91
+ "arrow-data",
92
+ "arrow-schema",
93
+ "chrono",
94
+ "half",
95
+ "hashbrown",
96
+ "num",
97
+ ]
98
+
99
+ [[package]]
100
+ name = "arrow-buffer"
101
+ version = "55.2.0"
102
+ source = "registry+https://github.com/rust-lang/crates.io-index"
103
+ checksum = "169b1d5d6cb390dd92ce582b06b23815c7953e9dfaaea75556e89d890d19993d"
104
+ dependencies = [
105
+ "bytes",
106
+ "half",
107
+ "num",
108
+ ]
109
+
110
+ [[package]]
111
+ name = "arrow-cast"
112
+ version = "55.2.0"
113
+ source = "registry+https://github.com/rust-lang/crates.io-index"
114
+ checksum = "e4f12eccc3e1c05a766cafb31f6a60a46c2f8efec9b74c6e0648766d30686af8"
115
+ dependencies = [
116
+ "arrow-array",
117
+ "arrow-buffer",
118
+ "arrow-data",
119
+ "arrow-schema",
120
+ "arrow-select",
121
+ "atoi",
122
+ "base64",
123
+ "chrono",
124
+ "half",
125
+ "lexical-core",
126
+ "num",
127
+ "ryu",
128
+ ]
129
+
130
+ [[package]]
131
+ name = "arrow-data"
132
+ version = "55.2.0"
133
+ source = "registry+https://github.com/rust-lang/crates.io-index"
134
+ checksum = "8de1ce212d803199684b658fc4ba55fb2d7e87b213de5af415308d2fee3619c2"
135
+ dependencies = [
136
+ "arrow-buffer",
137
+ "arrow-schema",
138
+ "half",
139
+ "num",
140
+ ]
141
+
142
+ [[package]]
143
+ name = "arrow-ord"
144
+ version = "55.2.0"
145
+ source = "registry+https://github.com/rust-lang/crates.io-index"
146
+ checksum = "6506e3a059e3be23023f587f79c82ef0bcf6d293587e3272d20f2d30b969b5a7"
147
+ dependencies = [
148
+ "arrow-array",
149
+ "arrow-buffer",
150
+ "arrow-data",
151
+ "arrow-schema",
152
+ "arrow-select",
153
+ ]
154
+
155
+ [[package]]
156
+ name = "arrow-pyarrow"
157
+ version = "55.2.0"
158
+ source = "registry+https://github.com/rust-lang/crates.io-index"
159
+ checksum = "0e55ecf16b9b61d433f6e63c72fc6afcf2597d7db96583de88ebb887d1822268"
160
+ dependencies = [
161
+ "arrow-array",
162
+ "arrow-data",
163
+ "arrow-schema",
164
+ "pyo3",
165
+ ]
166
+
167
+ [[package]]
168
+ name = "arrow-row"
169
+ version = "55.2.0"
170
+ source = "registry+https://github.com/rust-lang/crates.io-index"
171
+ checksum = "52bf7393166beaf79b4bed9bfdf19e97472af32ce5b6b48169d321518a08cae2"
172
+ dependencies = [
173
+ "arrow-array",
174
+ "arrow-buffer",
175
+ "arrow-data",
176
+ "arrow-schema",
177
+ "half",
178
+ ]
179
+
180
+ [[package]]
181
+ name = "arrow-schema"
182
+ version = "55.2.0"
183
+ source = "registry+https://github.com/rust-lang/crates.io-index"
184
+ checksum = "af7686986a3bf2254c9fb130c623cdcb2f8e1f15763e7c71c310f0834da3d292"
185
+ dependencies = [
186
+ "bitflags",
187
+ ]
188
+
189
+ [[package]]
190
+ name = "arrow-select"
191
+ version = "55.2.0"
192
+ source = "registry+https://github.com/rust-lang/crates.io-index"
193
+ checksum = "dd2b45757d6a2373faa3352d02ff5b54b098f5e21dccebc45a21806bc34501e5"
194
+ dependencies = [
195
+ "ahash",
196
+ "arrow-array",
197
+ "arrow-buffer",
198
+ "arrow-data",
199
+ "arrow-schema",
200
+ "num",
201
+ ]
202
+
203
+ [[package]]
204
+ name = "arrow-string"
205
+ version = "55.2.0"
206
+ source = "registry+https://github.com/rust-lang/crates.io-index"
207
+ checksum = "0377d532850babb4d927a06294314b316e23311503ed580ec6ce6a0158f49d40"
208
+ dependencies = [
209
+ "arrow-array",
210
+ "arrow-buffer",
211
+ "arrow-data",
212
+ "arrow-schema",
213
+ "arrow-select",
214
+ "memchr",
215
+ "num",
216
+ "regex",
217
+ "regex-syntax",
218
+ ]
219
+
220
+ [[package]]
221
+ name = "atoi"
222
+ version = "2.0.0"
223
+ source = "registry+https://github.com/rust-lang/crates.io-index"
224
+ checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
225
+ dependencies = [
226
+ "num-traits",
227
+ ]
228
+
229
+ [[package]]
230
+ name = "autocfg"
231
+ version = "1.5.1"
232
+ source = "registry+https://github.com/rust-lang/crates.io-index"
233
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
234
+
235
+ [[package]]
236
+ name = "base64"
237
+ version = "0.22.1"
238
+ source = "registry+https://github.com/rust-lang/crates.io-index"
239
+ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
240
+
241
+ [[package]]
242
+ name = "bitflags"
243
+ version = "2.13.0"
244
+ source = "registry+https://github.com/rust-lang/crates.io-index"
245
+ checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
246
+
247
+ [[package]]
248
+ name = "bumpalo"
249
+ version = "3.20.3"
250
+ source = "registry+https://github.com/rust-lang/crates.io-index"
251
+ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
252
+
253
+ [[package]]
254
+ name = "bytes"
255
+ version = "1.11.1"
256
+ source = "registry+https://github.com/rust-lang/crates.io-index"
257
+ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
258
+
259
+ [[package]]
260
+ name = "cc"
261
+ version = "1.2.63"
262
+ source = "registry+https://github.com/rust-lang/crates.io-index"
263
+ checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
264
+ dependencies = [
265
+ "find-msvc-tools",
266
+ "shlex",
267
+ ]
268
+
269
+ [[package]]
270
+ name = "cfg-if"
271
+ version = "1.0.4"
272
+ source = "registry+https://github.com/rust-lang/crates.io-index"
273
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
274
+
275
+ [[package]]
276
+ name = "chrono"
277
+ version = "0.4.45"
278
+ source = "registry+https://github.com/rust-lang/crates.io-index"
279
+ checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
280
+ dependencies = [
281
+ "iana-time-zone",
282
+ "num-traits",
283
+ "windows-link",
284
+ ]
285
+
286
+ [[package]]
287
+ name = "const-random"
288
+ version = "0.1.18"
289
+ source = "registry+https://github.com/rust-lang/crates.io-index"
290
+ checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
291
+ dependencies = [
292
+ "const-random-macro",
293
+ ]
294
+
295
+ [[package]]
296
+ name = "const-random-macro"
297
+ version = "0.1.16"
298
+ source = "registry+https://github.com/rust-lang/crates.io-index"
299
+ checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
300
+ dependencies = [
301
+ "getrandom 0.2.17",
302
+ "once_cell",
303
+ "tiny-keccak",
304
+ ]
305
+
306
+ [[package]]
307
+ name = "core-foundation-sys"
308
+ version = "0.8.7"
309
+ source = "registry+https://github.com/rust-lang/crates.io-index"
310
+ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
311
+
312
+ [[package]]
313
+ name = "crunchy"
314
+ version = "0.2.4"
315
+ source = "registry+https://github.com/rust-lang/crates.io-index"
316
+ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
317
+
318
+ [[package]]
319
+ name = "find-msvc-tools"
320
+ version = "0.1.9"
321
+ source = "registry+https://github.com/rust-lang/crates.io-index"
322
+ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
323
+
324
+ [[package]]
325
+ name = "futures-core"
326
+ version = "0.3.32"
327
+ source = "registry+https://github.com/rust-lang/crates.io-index"
328
+ checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
329
+
330
+ [[package]]
331
+ name = "futures-task"
332
+ version = "0.3.32"
333
+ source = "registry+https://github.com/rust-lang/crates.io-index"
334
+ checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
335
+
336
+ [[package]]
337
+ name = "futures-util"
338
+ version = "0.3.32"
339
+ source = "registry+https://github.com/rust-lang/crates.io-index"
340
+ checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
341
+ dependencies = [
342
+ "futures-core",
343
+ "futures-task",
344
+ "pin-project-lite",
345
+ "slab",
346
+ ]
347
+
348
+ [[package]]
349
+ name = "getrandom"
350
+ version = "0.2.17"
351
+ source = "registry+https://github.com/rust-lang/crates.io-index"
352
+ checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
353
+ dependencies = [
354
+ "cfg-if",
355
+ "libc",
356
+ "wasi",
357
+ ]
358
+
359
+ [[package]]
360
+ name = "getrandom"
361
+ version = "0.3.4"
362
+ source = "registry+https://github.com/rust-lang/crates.io-index"
363
+ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
364
+ dependencies = [
365
+ "cfg-if",
366
+ "libc",
367
+ "r-efi",
368
+ "wasip2",
369
+ ]
370
+
371
+ [[package]]
372
+ name = "half"
373
+ version = "2.7.1"
374
+ source = "registry+https://github.com/rust-lang/crates.io-index"
375
+ checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
376
+ dependencies = [
377
+ "cfg-if",
378
+ "crunchy",
379
+ "num-traits",
380
+ "zerocopy",
381
+ ]
382
+
383
+ [[package]]
384
+ name = "hashbrown"
385
+ version = "0.15.5"
386
+ source = "registry+https://github.com/rust-lang/crates.io-index"
387
+ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
388
+
389
+ [[package]]
390
+ name = "heck"
391
+ version = "0.5.0"
392
+ source = "registry+https://github.com/rust-lang/crates.io-index"
393
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
394
+
395
+ [[package]]
396
+ name = "iana-time-zone"
397
+ version = "0.1.65"
398
+ source = "registry+https://github.com/rust-lang/crates.io-index"
399
+ checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
400
+ dependencies = [
401
+ "android_system_properties",
402
+ "core-foundation-sys",
403
+ "iana-time-zone-haiku",
404
+ "js-sys",
405
+ "log",
406
+ "wasm-bindgen",
407
+ "windows-core",
408
+ ]
409
+
410
+ [[package]]
411
+ name = "iana-time-zone-haiku"
412
+ version = "0.1.2"
413
+ source = "registry+https://github.com/rust-lang/crates.io-index"
414
+ checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
415
+ dependencies = [
416
+ "cc",
417
+ ]
418
+
419
+ [[package]]
420
+ name = "indoc"
421
+ version = "2.0.7"
422
+ source = "registry+https://github.com/rust-lang/crates.io-index"
423
+ checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
424
+ dependencies = [
425
+ "rustversion",
426
+ ]
427
+
428
+ [[package]]
429
+ name = "js-sys"
430
+ version = "0.3.99"
431
+ source = "registry+https://github.com/rust-lang/crates.io-index"
432
+ checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
433
+ dependencies = [
434
+ "cfg-if",
435
+ "futures-util",
436
+ "once_cell",
437
+ "wasm-bindgen",
438
+ ]
439
+
440
+ [[package]]
441
+ name = "lexical-core"
442
+ version = "1.0.6"
443
+ source = "registry+https://github.com/rust-lang/crates.io-index"
444
+ checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594"
445
+ dependencies = [
446
+ "lexical-parse-float",
447
+ "lexical-parse-integer",
448
+ "lexical-util",
449
+ "lexical-write-float",
450
+ "lexical-write-integer",
451
+ ]
452
+
453
+ [[package]]
454
+ name = "lexical-parse-float"
455
+ version = "1.0.6"
456
+ source = "registry+https://github.com/rust-lang/crates.io-index"
457
+ checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56"
458
+ dependencies = [
459
+ "lexical-parse-integer",
460
+ "lexical-util",
461
+ ]
462
+
463
+ [[package]]
464
+ name = "lexical-parse-integer"
465
+ version = "1.0.6"
466
+ source = "registry+https://github.com/rust-lang/crates.io-index"
467
+ checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34"
468
+ dependencies = [
469
+ "lexical-util",
470
+ ]
471
+
472
+ [[package]]
473
+ name = "lexical-util"
474
+ version = "1.0.7"
475
+ source = "registry+https://github.com/rust-lang/crates.io-index"
476
+ checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17"
477
+
478
+ [[package]]
479
+ name = "lexical-write-float"
480
+ version = "1.0.6"
481
+ source = "registry+https://github.com/rust-lang/crates.io-index"
482
+ checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361"
483
+ dependencies = [
484
+ "lexical-util",
485
+ "lexical-write-integer",
486
+ ]
487
+
488
+ [[package]]
489
+ name = "lexical-write-integer"
490
+ version = "1.0.6"
491
+ source = "registry+https://github.com/rust-lang/crates.io-index"
492
+ checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df"
493
+ dependencies = [
494
+ "lexical-util",
495
+ ]
496
+
497
+ [[package]]
498
+ name = "libc"
499
+ version = "0.2.186"
500
+ source = "registry+https://github.com/rust-lang/crates.io-index"
501
+ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
502
+
503
+ [[package]]
504
+ name = "libm"
505
+ version = "0.2.16"
506
+ source = "registry+https://github.com/rust-lang/crates.io-index"
507
+ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
508
+
509
+ [[package]]
510
+ name = "log"
511
+ version = "0.4.32"
512
+ source = "registry+https://github.com/rust-lang/crates.io-index"
513
+ checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
514
+
515
+ [[package]]
516
+ name = "memchr"
517
+ version = "2.8.1"
518
+ source = "registry+https://github.com/rust-lang/crates.io-index"
519
+ checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
520
+
521
+ [[package]]
522
+ name = "memoffset"
523
+ version = "0.9.1"
524
+ source = "registry+https://github.com/rust-lang/crates.io-index"
525
+ checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
526
+ dependencies = [
527
+ "autocfg",
528
+ ]
529
+
530
+ [[package]]
531
+ name = "num"
532
+ version = "0.4.3"
533
+ source = "registry+https://github.com/rust-lang/crates.io-index"
534
+ checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
535
+ dependencies = [
536
+ "num-bigint",
537
+ "num-complex",
538
+ "num-integer",
539
+ "num-iter",
540
+ "num-rational",
541
+ "num-traits",
542
+ ]
543
+
544
+ [[package]]
545
+ name = "num-bigint"
546
+ version = "0.4.6"
547
+ source = "registry+https://github.com/rust-lang/crates.io-index"
548
+ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
549
+ dependencies = [
550
+ "num-integer",
551
+ "num-traits",
552
+ ]
553
+
554
+ [[package]]
555
+ name = "num-complex"
556
+ version = "0.4.6"
557
+ source = "registry+https://github.com/rust-lang/crates.io-index"
558
+ checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
559
+ dependencies = [
560
+ "num-traits",
561
+ ]
562
+
563
+ [[package]]
564
+ name = "num-integer"
565
+ version = "0.1.46"
566
+ source = "registry+https://github.com/rust-lang/crates.io-index"
567
+ checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
568
+ dependencies = [
569
+ "num-traits",
570
+ ]
571
+
572
+ [[package]]
573
+ name = "num-iter"
574
+ version = "0.1.45"
575
+ source = "registry+https://github.com/rust-lang/crates.io-index"
576
+ checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
577
+ dependencies = [
578
+ "autocfg",
579
+ "num-integer",
580
+ "num-traits",
581
+ ]
582
+
583
+ [[package]]
584
+ name = "num-rational"
585
+ version = "0.4.2"
586
+ source = "registry+https://github.com/rust-lang/crates.io-index"
587
+ checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
588
+ dependencies = [
589
+ "num-bigint",
590
+ "num-integer",
591
+ "num-traits",
592
+ ]
593
+
594
+ [[package]]
595
+ name = "num-traits"
596
+ version = "0.2.19"
597
+ source = "registry+https://github.com/rust-lang/crates.io-index"
598
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
599
+ dependencies = [
600
+ "autocfg",
601
+ "libm",
602
+ ]
603
+
604
+ [[package]]
605
+ name = "once_cell"
606
+ version = "1.21.4"
607
+ source = "registry+https://github.com/rust-lang/crates.io-index"
608
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
609
+
610
+ [[package]]
611
+ name = "pin-project-lite"
612
+ version = "0.2.17"
613
+ source = "registry+https://github.com/rust-lang/crates.io-index"
614
+ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
615
+
616
+ [[package]]
617
+ name = "portable-atomic"
618
+ version = "1.13.1"
619
+ source = "registry+https://github.com/rust-lang/crates.io-index"
620
+ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
621
+
622
+ [[package]]
623
+ name = "proc-macro2"
624
+ version = "1.0.106"
625
+ source = "registry+https://github.com/rust-lang/crates.io-index"
626
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
627
+ dependencies = [
628
+ "unicode-ident",
629
+ ]
630
+
631
+ [[package]]
632
+ name = "pyo3"
633
+ version = "0.24.2"
634
+ source = "registry+https://github.com/rust-lang/crates.io-index"
635
+ checksum = "e5203598f366b11a02b13aa20cab591229ff0a89fd121a308a5df751d5fc9219"
636
+ dependencies = [
637
+ "cfg-if",
638
+ "indoc",
639
+ "libc",
640
+ "memoffset",
641
+ "once_cell",
642
+ "portable-atomic",
643
+ "pyo3-build-config",
644
+ "pyo3-ffi",
645
+ "pyo3-macros",
646
+ "unindent",
647
+ ]
648
+
649
+ [[package]]
650
+ name = "pyo3-build-config"
651
+ version = "0.24.2"
652
+ source = "registry+https://github.com/rust-lang/crates.io-index"
653
+ checksum = "99636d423fa2ca130fa5acde3059308006d46f98caac629418e53f7ebb1e9999"
654
+ dependencies = [
655
+ "once_cell",
656
+ "target-lexicon",
657
+ ]
658
+
659
+ [[package]]
660
+ name = "pyo3-ffi"
661
+ version = "0.24.2"
662
+ source = "registry+https://github.com/rust-lang/crates.io-index"
663
+ checksum = "78f9cf92ba9c409279bc3305b5409d90db2d2c22392d443a87df3a1adad59e33"
664
+ dependencies = [
665
+ "libc",
666
+ "pyo3-build-config",
667
+ ]
668
+
669
+ [[package]]
670
+ name = "pyo3-macros"
671
+ version = "0.24.2"
672
+ source = "registry+https://github.com/rust-lang/crates.io-index"
673
+ checksum = "0b999cb1a6ce21f9a6b147dcf1be9ffedf02e0043aec74dc390f3007047cecd9"
674
+ dependencies = [
675
+ "proc-macro2",
676
+ "pyo3-macros-backend",
677
+ "quote",
678
+ "syn",
679
+ ]
680
+
681
+ [[package]]
682
+ name = "pyo3-macros-backend"
683
+ version = "0.24.2"
684
+ source = "registry+https://github.com/rust-lang/crates.io-index"
685
+ checksum = "822ece1c7e1012745607d5cf0bcb2874769f0f7cb34c4cde03b9358eb9ef911a"
686
+ dependencies = [
687
+ "heck",
688
+ "proc-macro2",
689
+ "pyo3-build-config",
690
+ "quote",
691
+ "syn",
692
+ ]
693
+
694
+ [[package]]
695
+ name = "quote"
696
+ version = "1.0.45"
697
+ source = "registry+https://github.com/rust-lang/crates.io-index"
698
+ checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
699
+ dependencies = [
700
+ "proc-macro2",
701
+ ]
702
+
703
+ [[package]]
704
+ name = "r-efi"
705
+ version = "5.3.0"
706
+ source = "registry+https://github.com/rust-lang/crates.io-index"
707
+ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
708
+
709
+ [[package]]
710
+ name = "regex"
711
+ version = "1.12.3"
712
+ source = "registry+https://github.com/rust-lang/crates.io-index"
713
+ checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
714
+ dependencies = [
715
+ "aho-corasick",
716
+ "memchr",
717
+ "regex-automata",
718
+ "regex-syntax",
719
+ ]
720
+
721
+ [[package]]
722
+ name = "regex-automata"
723
+ version = "0.4.14"
724
+ source = "registry+https://github.com/rust-lang/crates.io-index"
725
+ checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
726
+ dependencies = [
727
+ "aho-corasick",
728
+ "memchr",
729
+ "regex-syntax",
730
+ ]
731
+
732
+ [[package]]
733
+ name = "regex-syntax"
734
+ version = "0.8.10"
735
+ source = "registry+https://github.com/rust-lang/crates.io-index"
736
+ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
737
+
738
+ [[package]]
739
+ name = "rustversion"
740
+ version = "1.0.22"
741
+ source = "registry+https://github.com/rust-lang/crates.io-index"
742
+ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
743
+
744
+ [[package]]
745
+ name = "ryu"
746
+ version = "1.0.23"
747
+ source = "registry+https://github.com/rust-lang/crates.io-index"
748
+ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
749
+
750
+ [[package]]
751
+ name = "shlex"
752
+ version = "2.0.1"
753
+ source = "registry+https://github.com/rust-lang/crates.io-index"
754
+ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
755
+
756
+ [[package]]
757
+ name = "slab"
758
+ version = "0.4.12"
759
+ source = "registry+https://github.com/rust-lang/crates.io-index"
760
+ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
761
+
762
+ [[package]]
763
+ name = "syn"
764
+ version = "2.0.117"
765
+ source = "registry+https://github.com/rust-lang/crates.io-index"
766
+ checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
767
+ dependencies = [
768
+ "proc-macro2",
769
+ "quote",
770
+ "unicode-ident",
771
+ ]
772
+
773
+ [[package]]
774
+ name = "target-lexicon"
775
+ version = "0.13.5"
776
+ source = "registry+https://github.com/rust-lang/crates.io-index"
777
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
778
+
779
+ [[package]]
780
+ name = "tiny-keccak"
781
+ version = "2.0.2"
782
+ source = "registry+https://github.com/rust-lang/crates.io-index"
783
+ checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
784
+ dependencies = [
785
+ "crunchy",
786
+ ]
787
+
788
+ [[package]]
789
+ name = "unicode-ident"
790
+ version = "1.0.24"
791
+ source = "registry+https://github.com/rust-lang/crates.io-index"
792
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
793
+
794
+ [[package]]
795
+ name = "unindent"
796
+ version = "0.2.4"
797
+ source = "registry+https://github.com/rust-lang/crates.io-index"
798
+ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
799
+
800
+ [[package]]
801
+ name = "version_check"
802
+ version = "0.9.5"
803
+ source = "registry+https://github.com/rust-lang/crates.io-index"
804
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
805
+
806
+ [[package]]
807
+ name = "wasi"
808
+ version = "0.11.1+wasi-snapshot-preview1"
809
+ source = "registry+https://github.com/rust-lang/crates.io-index"
810
+ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
811
+
812
+ [[package]]
813
+ name = "wasip2"
814
+ version = "1.0.3+wasi-0.2.9"
815
+ source = "registry+https://github.com/rust-lang/crates.io-index"
816
+ checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
817
+ dependencies = [
818
+ "wit-bindgen",
819
+ ]
820
+
821
+ [[package]]
822
+ name = "wasm-bindgen"
823
+ version = "0.2.122"
824
+ source = "registry+https://github.com/rust-lang/crates.io-index"
825
+ checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
826
+ dependencies = [
827
+ "cfg-if",
828
+ "once_cell",
829
+ "rustversion",
830
+ "wasm-bindgen-macro",
831
+ "wasm-bindgen-shared",
832
+ ]
833
+
834
+ [[package]]
835
+ name = "wasm-bindgen-macro"
836
+ version = "0.2.122"
837
+ source = "registry+https://github.com/rust-lang/crates.io-index"
838
+ checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
839
+ dependencies = [
840
+ "quote",
841
+ "wasm-bindgen-macro-support",
842
+ ]
843
+
844
+ [[package]]
845
+ name = "wasm-bindgen-macro-support"
846
+ version = "0.2.122"
847
+ source = "registry+https://github.com/rust-lang/crates.io-index"
848
+ checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
849
+ dependencies = [
850
+ "bumpalo",
851
+ "proc-macro2",
852
+ "quote",
853
+ "syn",
854
+ "wasm-bindgen-shared",
855
+ ]
856
+
857
+ [[package]]
858
+ name = "wasm-bindgen-shared"
859
+ version = "0.2.122"
860
+ source = "registry+https://github.com/rust-lang/crates.io-index"
861
+ checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
862
+ dependencies = [
863
+ "unicode-ident",
864
+ ]
865
+
866
+ [[package]]
867
+ name = "windows-core"
868
+ version = "0.62.2"
869
+ source = "registry+https://github.com/rust-lang/crates.io-index"
870
+ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
871
+ dependencies = [
872
+ "windows-implement",
873
+ "windows-interface",
874
+ "windows-link",
875
+ "windows-result",
876
+ "windows-strings",
877
+ ]
878
+
879
+ [[package]]
880
+ name = "windows-implement"
881
+ version = "0.60.2"
882
+ source = "registry+https://github.com/rust-lang/crates.io-index"
883
+ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
884
+ dependencies = [
885
+ "proc-macro2",
886
+ "quote",
887
+ "syn",
888
+ ]
889
+
890
+ [[package]]
891
+ name = "windows-interface"
892
+ version = "0.59.3"
893
+ source = "registry+https://github.com/rust-lang/crates.io-index"
894
+ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
895
+ dependencies = [
896
+ "proc-macro2",
897
+ "quote",
898
+ "syn",
899
+ ]
900
+
901
+ [[package]]
902
+ name = "windows-link"
903
+ version = "0.2.1"
904
+ source = "registry+https://github.com/rust-lang/crates.io-index"
905
+ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
906
+
907
+ [[package]]
908
+ name = "windows-result"
909
+ version = "0.4.1"
910
+ source = "registry+https://github.com/rust-lang/crates.io-index"
911
+ checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
912
+ dependencies = [
913
+ "windows-link",
914
+ ]
915
+
916
+ [[package]]
917
+ name = "windows-strings"
918
+ version = "0.5.1"
919
+ source = "registry+https://github.com/rust-lang/crates.io-index"
920
+ checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
921
+ dependencies = [
922
+ "windows-link",
923
+ ]
924
+
925
+ [[package]]
926
+ name = "wit-bindgen"
927
+ version = "0.57.1"
928
+ source = "registry+https://github.com/rust-lang/crates.io-index"
929
+ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
930
+
931
+ [[package]]
932
+ name = "zerocopy"
933
+ version = "0.8.50"
934
+ source = "registry+https://github.com/rust-lang/crates.io-index"
935
+ checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1"
936
+ dependencies = [
937
+ "zerocopy-derive",
938
+ ]
939
+
940
+ [[package]]
941
+ name = "zerocopy-derive"
942
+ version = "0.8.50"
943
+ source = "registry+https://github.com/rust-lang/crates.io-index"
944
+ checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639"
945
+ dependencies = [
946
+ "proc-macro2",
947
+ "quote",
948
+ "syn",
949
+ ]
@@ -0,0 +1,37 @@
1
+ # Standalone workspace (empty [workspace]) so pyo3's `extension-module` feature
2
+ # here is NOT unified with the `bridge` crate's `auto-initialize` feature -- the
3
+ # two are mutually incompatible (ext-module must NOT link libpython; embedding
4
+ # must). Mirrors goldencheck-native / goldenmatch's `native` crate.
5
+ [workspace]
6
+
7
+ [package]
8
+ name = "analysis-native"
9
+ version = "0.1.0"
10
+ edition = "2021"
11
+ license = "MIT"
12
+ authors = ["Ben Severn <ben@bensevern.dev>"]
13
+ description = "Native acceleration kernels for GoldenAnalysis (PyO3 extension module)"
14
+ readme = "README.md"
15
+
16
+ [lib]
17
+ # Produces lib_native.so; renamed to goldenanalysis/_native.abi3.so at install
18
+ # (scripts/build_analysis_native.py), or shipped as goldenanalysis_native/_native
19
+ # by maturin. The #[pymodule] is `_native`, so the init symbol is PyInit__native.
20
+ name = "_native"
21
+ crate-type = ["cdylib"]
22
+
23
+ [dependencies]
24
+ # abi3-py311: one stable-ABI artifact spans CPython 3.11-3.13.
25
+ # extension-module: don't link libpython (this .so is imported BY CPython).
26
+ pyo3 = { version = ">=0.23.3, <0.25", features = ["extension-module", "abi3-py311"] }
27
+ # Pyo3-free histogram/quantile kernels; the #[pyfunction] shims below are thin
28
+ # Arrow-reading wrappers over this crate.
29
+ analysis-core = { path = "../analysis-core" }
30
+ # Arrow C Data Interface for zero-copy kernel input (mirrors goldencheck-native).
31
+ # `pyarrow` brings the PyArrowType FFI bridge; default features (csv/ipc/json/
32
+ # compute) are off -- we only read array buffers.
33
+ arrow = { version = "55", default-features = false, features = ["pyarrow"] }
34
+
35
+ [profile.release]
36
+ opt-level = 3
37
+ lto = "thin"
@@ -0,0 +1,25 @@
1
+ # goldenanalysis-native
2
+
3
+ Optional native (Rust/PyO3) acceleration kernels for
4
+ [`goldenanalysis`](https://github.com/benseverndev-oss/goldenmatch/tree/main/packages/python/goldenanalysis).
5
+
6
+ You don't import this directly. `goldenanalysis` stays a pure-Python wheel;
7
+ `pip install goldenanalysis[native]` pulls this compiled abi3 wheel, and
8
+ `goldenanalysis.core._native_loader` discovers it (falling back to the pure-Python
9
+ path when it isn't present).
10
+
11
+ The kernel mirrors the pure-Python aggregation loops in
12
+ `goldenanalysis/core/aggregate.py` (`histogram`, `quantile`) value-for-value, reading
13
+ input as a Float64 Arrow array (zero-copy, C Data Interface). A primitive is only
14
+ used under `GOLDENANALYSIS_NATIVE=auto` once it has cleared
15
+ `_native_loader._GATED_ON` — proven byte-identical **and** measured to move the wall
16
+ on a real shape. The two-crate split (pyo3-free `analysis-core` + this abi3 shim)
17
+ mirrors `goldencheck-core`/`goldencheck-native`.
18
+
19
+ Build in-tree for local dev (drops `goldenanalysis/_native.abi3.so`):
20
+
21
+ ```bash
22
+ uv run python scripts/build_analysis_native.py
23
+ ```
24
+
25
+ MIT.
@@ -0,0 +1,62 @@
1
+ //! `goldenanalysis._native` -- native acceleration kernels (PyO3 extension module).
2
+ //!
3
+ //! Thin Arrow-reading shims over the pyo3-free `analysis-core` crate. Each
4
+ //! function is a behaviour-exact replacement for a CPU-bound pure-Python loop in
5
+ //! `goldenanalysis/core/aggregate.py`; the Python side
6
+ //! (`goldenanalysis/core/_native_loader.py`) selects the native path only when
7
+ //! `GOLDENANALYSIS_NATIVE` opts in AND the primitive has cleared parity
8
+ //! (`_GATED_ON`, empty until a wall-verified flip), and the pure-Python
9
+ //! implementation stays the default + fallback.
10
+ //!
11
+ //! Data crosses the boundary as a Float64 Arrow array via the C Data Interface
12
+ //! (`PyArrowType<ArrayData>`), zero-copy, mirroring goldencheck-native. The shims
13
+ //! never touch business logic -- they decode Arrow into a plain `&[f64]` (dropping
14
+ //! null slots, whose backing value is undefined) and delegate to `analysis-core`.
15
+ use arrow::array::{Array, ArrayData, Float64Array};
16
+ use arrow::pyarrow::PyArrowType;
17
+ use pyo3::prelude::*;
18
+
19
+ /// Read a Float64 Arrow array into a `Vec<f64>`, dropping null slots. Raises
20
+ /// `TypeError` on non-Float64 input (cast in Polars before `.to_arrow()`).
21
+ fn read_f64(values: PyArrowType<ArrayData>, fn_name: &str) -> PyResult<Vec<f64>> {
22
+ let data = values.0;
23
+ if !matches!(data.data_type(), arrow::datatypes::DataType::Float64) {
24
+ return Err(pyo3::exceptions::PyTypeError::new_err(format!(
25
+ "{fn_name} expects a Float64 array, got {:?}",
26
+ data.data_type()
27
+ )));
28
+ }
29
+ let arr = Float64Array::from(data);
30
+ Ok(if arr.null_count() == 0 {
31
+ arr.values().to_vec()
32
+ } else {
33
+ (0..arr.len())
34
+ .filter(|&i| !arr.is_null(i))
35
+ .map(|i| arr.value(i))
36
+ .collect()
37
+ })
38
+ }
39
+
40
+ /// Equal-width histogram over a Float64 Arrow column -- the native mirror of
41
+ /// `goldenanalysis.core.aggregate.histogram`. Returns `[(left_edge, count), ...]`.
42
+ #[pyfunction]
43
+ fn histogram(values: PyArrowType<ArrayData>, bins: i64) -> PyResult<Vec<(f64, i64)>> {
44
+ let vals = read_f64(values, "histogram")?;
45
+ Ok(analysis_core::histogram(&vals, bins))
46
+ }
47
+
48
+ /// Linear-interpolation quantile of a Float64 Arrow column -- the native mirror of
49
+ /// `goldenanalysis.core.aggregate.quantile`.
50
+ #[pyfunction]
51
+ fn quantile(values: PyArrowType<ArrayData>, q: f64) -> PyResult<f64> {
52
+ let vals = read_f64(values, "quantile")?;
53
+ Ok(analysis_core::quantile(&vals, q))
54
+ }
55
+
56
+ #[pymodule]
57
+ fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> {
58
+ m.add("__version__", env!("CARGO_PKG_VERSION"))?;
59
+ m.add_function(wrap_pyfunction!(histogram, m)?)?;
60
+ m.add_function(wrap_pyfunction!(quantile, m)?)?;
61
+ Ok(())
62
+ }
@@ -0,0 +1,39 @@
1
+ # goldenanalysis-native -- the optional native acceleration runtime for
2
+ # GoldenAnalysis, shipped as a SEPARATE maturin/abi3 package (mirrors goldencheck's
3
+ # native / goldencheck-native split). `goldenanalysis` stays a pure-Python wheel;
4
+ # `pip install goldenanalysis[native]` pulls this, and
5
+ # goldenanalysis.core._native_loader discovers it.
6
+ #
7
+ # The crate also builds via scripts/build_analysis_native.py for in-tree local dev
8
+ # (drops goldenanalysis/_native.abi3.so); both paths share the same `_native`
9
+ # pymodule, so the loader can import either.
10
+ [build-system]
11
+ requires = ["maturin>=1.7,<2"]
12
+ build-backend = "maturin"
13
+
14
+ [project]
15
+ name = "goldenanalysis-native"
16
+ version = "0.1.0"
17
+ description = "Optional native (Rust/PyO3) acceleration kernels for goldenanalysis"
18
+ readme = "README.md"
19
+ requires-python = ">=3.11"
20
+ license = { text = "MIT" }
21
+ authors = [{ name = "Ben Severn", email = "ben@bensevern.dev" }]
22
+ classifiers = [
23
+ "Programming Language :: Rust",
24
+ "Programming Language :: Python :: 3 :: Only",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Intended Audience :: Developers",
27
+ "Topic :: Scientific/Engineering",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/benseverndev-oss/goldenmatch"
32
+
33
+ [tool.maturin]
34
+ module-name = "goldenanalysis_native._native"
35
+ manifest-path = "analysis-native/Cargo.toml"
36
+ python-source = "python"
37
+ # One abi3 wheel per platform spans CPython 3.11-3.13 (pyo3 abi3-py311 in
38
+ # Cargo.toml). extension-module (no libpython link) is already a default pyo3
39
+ # feature on the crate, so maturin inherits it.
@@ -0,0 +1,22 @@
1
+ """goldenanalysis-native -- optional Rust/PyO3 acceleration kernels for goldenanalysis.
2
+
3
+ This package ships ONLY the compiled abi3 ``_native`` extension. You don't import
4
+ it directly; ``goldenanalysis`` discovers it through
5
+ ``goldenanalysis.core._native_loader`` when present and falls back to its pure-
6
+ Python paths when it isn't. Mirrors goldencheck's native / goldencheck-native
7
+ split: the frontend (``goldenanalysis``) stays a pure-Python wheel, the compiled
8
+ runtime ships separately and is pulled in via ``pip install goldenanalysis[native]``.
9
+ """
10
+
11
+ from . import _native as _native # the compiled abi3 extension module
12
+
13
+ __all__ = ["_native"]
14
+
15
+ # Read the version from the installed distribution metadata (maturin sets it from
16
+ # pyproject `[project].version`) so it can never drift from the wheel.
17
+ from importlib.metadata import PackageNotFoundError, version as _pkg_version
18
+
19
+ try:
20
+ __version__ = _pkg_version("goldenanalysis-native")
21
+ except PackageNotFoundError: # source checkout without installed dist metadata
22
+ __version__ = "0.1.0"