jsonatapy 2.2.1__tar.gz → 2.2.2__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.
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.gitignore +5 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/CHANGELOG.md +28 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/Cargo.lock +17 -17
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/Cargo.toml +1 -1
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/PKG-INFO +2 -2
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/README.md +1 -1
- jsonatapy-2.2.2/examples/simd_json_bench.rs +126 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/pyproject.toml +1 -1
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/value.rs +24 -5
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.gitmodules +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/.gitignore +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/memories/architecture.md +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/memories/conventions.md +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/memories/core.md +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/memories/memory_maintenance.md +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/memories/suggested_commands.md +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/memories/task_completion.md +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/memories/tech_stack.md +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/.serena/project.yml +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/LICENSE +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/benches/evaluator_bench.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/examples/evaluator_demo.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/examples/parser_demo.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/python/jsonatapy/__init__.py +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/python/jsonatapy/py.typed +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/ast.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/ast_transform.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/compiler.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/datetime.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/evaluator.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/functions.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/lib.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/parser/README.md +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/parser.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/signature.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/src/vm.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/tests/datetime_picture_suite.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/tests/integration_test.rs +0 -0
- {jsonatapy-2.2.1 → jsonatapy-2.2.2}/tests/parent_and_focus_binding_suite.rs +0 -0
|
@@ -63,6 +63,11 @@ benchmarks/javascript/package-lock.json
|
|
|
63
63
|
# Test artifacts
|
|
64
64
|
# tests/jsonata-js/ - Now a git submodule, don't ignore
|
|
65
65
|
|
|
66
|
+
# Claude Code local settings (personal per-developer permissions/config,
|
|
67
|
+
# not meant to be shared across the team)
|
|
68
|
+
.claude/settings.local.json
|
|
69
|
+
.claude/worktrees/
|
|
70
|
+
|
|
66
71
|
# Temporary files
|
|
67
72
|
*.tmp
|
|
68
73
|
*.bak
|
|
@@ -19,6 +19,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
19
19
|
|
|
20
20
|
### Security
|
|
21
21
|
|
|
22
|
+
## [2.2.2] - 2026-07-09
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- Documented `JsonataData`, `evaluate_with_data`, and `evaluate_data_to_json` in `docs/api.md`
|
|
26
|
+
(previously absent from the API reference entirely, despite being the "3-15x faster"
|
|
27
|
+
pre-converted-data path highlighted in the README's Performance section). Added a cross-link
|
|
28
|
+
from `docs/rust-crate.md` to the full auto-generated API reference on docs.rs. (#65)
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- Updated Rust dependencies to the latest versions compatible with existing (unpinned) semver
|
|
32
|
+
requirements: `simd-json` 0.17.0 → 0.17.2 plus 6 transitive patch bumps. No security advisories
|
|
33
|
+
found before or after (`cargo deny check`). (#65)
|
|
34
|
+
|
|
35
|
+
### Deprecated
|
|
36
|
+
|
|
37
|
+
### Removed
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
- SIMD-accelerated JSON parsing (`simd-json` feature, on by default) was consistently *slower*
|
|
41
|
+
than the plain `serde_json` fallback for most payload sizes (up to 29% slower at 180KB), the
|
|
42
|
+
opposite of its intent — caused by allocating fresh internal scratch buffers on every single
|
|
43
|
+
parse call. Fixed by reusing a thread-local scratch buffer across calls; SIMD parsing now beats
|
|
44
|
+
`serde_json` consistently (up to +22% faster) instead of losing at 3 of 4 tested sizes.
|
|
45
|
+
Also corrected the README's "(optional feature)" wording for SIMD, which implied opt-in when
|
|
46
|
+
it's actually enabled by default, including in published wheels. (#65)
|
|
47
|
+
|
|
48
|
+
### Security
|
|
49
|
+
|
|
22
50
|
## [2.2.1] - 2026-07-08
|
|
23
51
|
|
|
24
52
|
> Same code as [2.1.7](#217---2026-07-08) below, renumbered. This project's release versions
|
|
@@ -103,9 +103,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
|
|
103
103
|
|
|
104
104
|
[[package]]
|
|
105
105
|
name = "cc"
|
|
106
|
-
version = "1.2.
|
|
106
|
+
version = "1.2.66"
|
|
107
107
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
108
|
-
checksum = "
|
|
108
|
+
checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996"
|
|
109
109
|
dependencies = [
|
|
110
110
|
"find-msvc-tools",
|
|
111
111
|
"shlex",
|
|
@@ -245,9 +245,9 @@ dependencies = [
|
|
|
245
245
|
|
|
246
246
|
[[package]]
|
|
247
247
|
name = "crossbeam-deque"
|
|
248
|
-
version = "0.8.
|
|
248
|
+
version = "0.8.7"
|
|
249
249
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
250
|
-
checksum = "
|
|
250
|
+
checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb"
|
|
251
251
|
dependencies = [
|
|
252
252
|
"crossbeam-epoch",
|
|
253
253
|
"crossbeam-utils",
|
|
@@ -264,9 +264,9 @@ dependencies = [
|
|
|
264
264
|
|
|
265
265
|
[[package]]
|
|
266
266
|
name = "crossbeam-utils"
|
|
267
|
-
version = "0.8.
|
|
267
|
+
version = "0.8.22"
|
|
268
268
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
269
|
-
checksum = "
|
|
269
|
+
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
|
|
270
270
|
|
|
271
271
|
[[package]]
|
|
272
272
|
name = "crunchy"
|
|
@@ -483,7 +483,7 @@ dependencies = [
|
|
|
483
483
|
|
|
484
484
|
[[package]]
|
|
485
485
|
name = "jsonata-core"
|
|
486
|
-
version = "2.2.
|
|
486
|
+
version = "2.2.2"
|
|
487
487
|
dependencies = [
|
|
488
488
|
"base64",
|
|
489
489
|
"chrono",
|
|
@@ -522,9 +522,9 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
|
|
522
522
|
|
|
523
523
|
[[package]]
|
|
524
524
|
name = "memchr"
|
|
525
|
-
version = "2.8.
|
|
525
|
+
version = "2.8.3"
|
|
526
526
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
527
|
-
checksum = "
|
|
527
|
+
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
528
528
|
|
|
529
529
|
[[package]]
|
|
530
530
|
name = "num-traits"
|
|
@@ -882,9 +882,9 @@ dependencies = [
|
|
|
882
882
|
|
|
883
883
|
[[package]]
|
|
884
884
|
name = "rustversion"
|
|
885
|
-
version = "1.0.
|
|
885
|
+
version = "1.0.23"
|
|
886
886
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
887
|
-
checksum = "
|
|
887
|
+
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
|
888
888
|
|
|
889
889
|
[[package]]
|
|
890
890
|
name = "rusty-fork"
|
|
@@ -965,9 +965,9 @@ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
|
|
965
965
|
|
|
966
966
|
[[package]]
|
|
967
967
|
name = "simd-json"
|
|
968
|
-
version = "0.17.
|
|
968
|
+
version = "0.17.2"
|
|
969
969
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
970
|
-
checksum = "
|
|
970
|
+
checksum = "6f75934ad5ee9e78b79ce7731b822debcb3e5fa6c5aabe57410084715897d1ee"
|
|
971
971
|
dependencies = [
|
|
972
972
|
"halfbrown",
|
|
973
973
|
"ref-cast",
|
|
@@ -1276,18 +1276,18 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
|
|
1276
1276
|
|
|
1277
1277
|
[[package]]
|
|
1278
1278
|
name = "zerocopy"
|
|
1279
|
-
version = "0.8.
|
|
1279
|
+
version = "0.8.54"
|
|
1280
1280
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1281
|
-
checksum = "
|
|
1281
|
+
checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19"
|
|
1282
1282
|
dependencies = [
|
|
1283
1283
|
"zerocopy-derive",
|
|
1284
1284
|
]
|
|
1285
1285
|
|
|
1286
1286
|
[[package]]
|
|
1287
1287
|
name = "zerocopy-derive"
|
|
1288
|
-
version = "0.8.
|
|
1288
|
+
version = "0.8.54"
|
|
1289
1289
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1290
|
-
checksum = "
|
|
1290
|
+
checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5"
|
|
1291
1291
|
dependencies = [
|
|
1292
1292
|
"proc-macro2",
|
|
1293
1293
|
"quote",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jsonatapy
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -180,7 +180,7 @@ benchmark methodology.
|
|
|
180
180
|
- **Pure Rust core** — no JavaScript runtime, no Node.js dependency
|
|
181
181
|
- **Optional Python bindings** — PyO3/maturin, zero-copy where possible
|
|
182
182
|
- **Cross-platform** — Linux, macOS (Intel & ARM), Windows; Python 3.10–3.14
|
|
183
|
-
- **SIMD-accelerated JSON parsing** — via `simd-json
|
|
183
|
+
- **SIMD-accelerated JSON parsing** — via `simd-json`, enabled by default (disable with `--no-default-features`)
|
|
184
184
|
|
|
185
185
|
---
|
|
186
186
|
|
|
@@ -135,7 +135,7 @@ benchmark methodology.
|
|
|
135
135
|
- **Pure Rust core** — no JavaScript runtime, no Node.js dependency
|
|
136
136
|
- **Optional Python bindings** — PyO3/maturin, zero-copy where possible
|
|
137
137
|
- **Cross-platform** — Linux, macOS (Intel & ARM), Windows; Python 3.10–3.14
|
|
138
|
-
- **SIMD-accelerated JSON parsing** — via `simd-json
|
|
138
|
+
- **SIMD-accelerated JSON parsing** — via `simd-json`, enabled by default (disable with `--no-default-features`)
|
|
139
139
|
|
|
140
140
|
---
|
|
141
141
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
//! One-off benchmark: how much does the `simd` feature speed up JSON parsing?
|
|
2
|
+
//!
|
|
3
|
+
//! Run with the feature on (default) vs off, e.g.:
|
|
4
|
+
//! cargo run --release --example simd_json_bench
|
|
5
|
+
//! cargo run --release --example simd_json_bench --no-default-features
|
|
6
|
+
//!
|
|
7
|
+
//! Not part of the permanent benchmark suite - a throwaway comparison.
|
|
8
|
+
|
|
9
|
+
use jsonata_core::value::JValue;
|
|
10
|
+
use std::time::Instant;
|
|
11
|
+
|
|
12
|
+
fn ecommerce_json(n: usize) -> String {
|
|
13
|
+
let products: Vec<String> = (0..n)
|
|
14
|
+
.map(|i| {
|
|
15
|
+
format!(
|
|
16
|
+
r#"{{"id":{i},"name":"Product {i}","category":"{cat}","price":{price},"inStock":{stock},"rating":{rating},"reviews":{reviews},"tags":["tag1","tag2","tag3"],"vendor":{{"name":"Vendor {v}","rating":4.2}}}}"#,
|
|
17
|
+
i = i,
|
|
18
|
+
cat = ["Electronics", "Clothing", "Books", "Home"][i % 4],
|
|
19
|
+
price = 10.0 + i as f64 * 5.5,
|
|
20
|
+
stock = i % 3 != 0,
|
|
21
|
+
rating = 3.0 + (i % 3) as f64 * 0.5,
|
|
22
|
+
reviews = i * 2,
|
|
23
|
+
v = i % 10,
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
.collect();
|
|
27
|
+
format!(r#"{{"products":[{}]}}"#, products.join(","))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const REPEAT_TRIALS: usize = 5;
|
|
31
|
+
|
|
32
|
+
fn bench_parse(label: &str, json: &str, iterations: usize) {
|
|
33
|
+
// warmup (shared across all trials)
|
|
34
|
+
for _ in 0..(iterations / 10).max(10) {
|
|
35
|
+
let _ = JValue::from_json_str(json).unwrap();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Take the min across REPEAT_TRIALS independent trials - single-sample
|
|
39
|
+
// wall-clock timing is noisy enough to be meaningless on its own (see
|
|
40
|
+
// this project's own benchmarks/python/benchmark.py for why).
|
|
41
|
+
let mut best_ms: Option<f64> = None;
|
|
42
|
+
let mut all_ms = Vec::with_capacity(REPEAT_TRIALS);
|
|
43
|
+
for _ in 0..REPEAT_TRIALS {
|
|
44
|
+
let start = Instant::now();
|
|
45
|
+
for _ in 0..iterations {
|
|
46
|
+
let _ = JValue::from_json_str(json).unwrap();
|
|
47
|
+
}
|
|
48
|
+
let ms = start.elapsed().as_secs_f64() * 1000.0;
|
|
49
|
+
all_ms.push(ms);
|
|
50
|
+
best_ms = Some(best_ms.map_or(ms, |b: f64| b.min(ms)));
|
|
51
|
+
}
|
|
52
|
+
let best_ms = best_ms.unwrap();
|
|
53
|
+
let per_iter = best_ms / iterations as f64;
|
|
54
|
+
println!(
|
|
55
|
+
"{label:<28} {bytes:>8} bytes {iterations:>6} iters min={min:>8.2}ms all={all:?} {per:>10.5} ms/iter",
|
|
56
|
+
label = label,
|
|
57
|
+
bytes = json.len(),
|
|
58
|
+
iterations = iterations,
|
|
59
|
+
min = best_ms,
|
|
60
|
+
all = all_ms.iter().map(|v| format!("{v:.1}")).collect::<Vec<_>>(),
|
|
61
|
+
per = per_iter,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[cfg(feature = "simd")]
|
|
66
|
+
fn bench_parse_reused_buffer(label: &str, json: &str, iterations: usize) {
|
|
67
|
+
use simd_json::Buffers;
|
|
68
|
+
|
|
69
|
+
let mut buffers = Buffers::new(json.len() + 64);
|
|
70
|
+
let mut bytes = json.as_bytes().to_vec();
|
|
71
|
+
|
|
72
|
+
// warmup
|
|
73
|
+
for _ in 0..(iterations / 10).max(10) {
|
|
74
|
+
let _: JValue =
|
|
75
|
+
simd_json::serde::from_slice_with_buffers(&mut bytes, &mut buffers).unwrap();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let mut best_ms: Option<f64> = None;
|
|
79
|
+
let mut all_ms = Vec::with_capacity(REPEAT_TRIALS);
|
|
80
|
+
for _ in 0..REPEAT_TRIALS {
|
|
81
|
+
let start = Instant::now();
|
|
82
|
+
for _ in 0..iterations {
|
|
83
|
+
bytes.clear();
|
|
84
|
+
bytes.extend_from_slice(json.as_bytes());
|
|
85
|
+
let _: JValue =
|
|
86
|
+
simd_json::serde::from_slice_with_buffers(&mut bytes, &mut buffers).unwrap();
|
|
87
|
+
}
|
|
88
|
+
let ms = start.elapsed().as_secs_f64() * 1000.0;
|
|
89
|
+
all_ms.push(ms);
|
|
90
|
+
best_ms = Some(best_ms.map_or(ms, |b: f64| b.min(ms)));
|
|
91
|
+
}
|
|
92
|
+
let best_ms = best_ms.unwrap();
|
|
93
|
+
let per_iter = best_ms / iterations as f64;
|
|
94
|
+
println!(
|
|
95
|
+
"{label:<28} {bytes:>8} bytes {iterations:>6} iters min={min:>8.2}ms all={all:?} {per:>10.5} ms/iter",
|
|
96
|
+
label = label,
|
|
97
|
+
bytes = json.len(),
|
|
98
|
+
iterations = iterations,
|
|
99
|
+
min = best_ms,
|
|
100
|
+
all = all_ms.iter().map(|v| format!("{v:.1}")).collect::<Vec<_>>(),
|
|
101
|
+
per = per_iter,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fn main() {
|
|
106
|
+
let feature = if cfg!(feature = "simd") {
|
|
107
|
+
"simd-json"
|
|
108
|
+
} else {
|
|
109
|
+
"serde_json (simd off)"
|
|
110
|
+
};
|
|
111
|
+
println!("=== JSON parsing benchmark - active parser: {feature} ===\n");
|
|
112
|
+
|
|
113
|
+
bench_parse("tiny (1 product)", &ecommerce_json(1), 200_000);
|
|
114
|
+
bench_parse("small (10 products)", &ecommerce_json(10), 50_000);
|
|
115
|
+
bench_parse("medium (100 products)", &ecommerce_json(100), 5_000);
|
|
116
|
+
bench_parse("large (1000 products)", &ecommerce_json(1000), 500);
|
|
117
|
+
|
|
118
|
+
#[cfg(feature = "simd")]
|
|
119
|
+
{
|
|
120
|
+
println!("\n=== HYPOTHESIS TEST: simd-json with a REUSED Buffers scratch ===\n");
|
|
121
|
+
bench_parse_reused_buffer("tiny (1 product)", &ecommerce_json(1), 200_000);
|
|
122
|
+
bench_parse_reused_buffer("small (10 products)", &ecommerce_json(10), 50_000);
|
|
123
|
+
bench_parse_reused_buffer("medium (100 products)", &ecommerce_json(100), 5_000);
|
|
124
|
+
bench_parse_reused_buffer("large (1000 products)", &ecommerce_json(1000), 500);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "jsonatapy"
|
|
7
|
-
version = "2.2.
|
|
7
|
+
version = "2.2.2"
|
|
8
8
|
description = "High-performance Python/Rust implementation of JSONata query and transformation language"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "txjmb", email = "txjmb@users.noreply.github.com"}
|
|
@@ -572,14 +572,33 @@ impl JValue {
|
|
|
572
572
|
|
|
573
573
|
/// Parse a JSON string into a JValue (single-pass, no intermediate serde_json::Value).
|
|
574
574
|
///
|
|
575
|
-
/// When the `simd` feature is enabled, uses simd-json for
|
|
576
|
-
///
|
|
575
|
+
/// When the `simd` feature is enabled, uses simd-json for faster parsing on CPUs
|
|
576
|
+
/// with SIMD support (SSE4.2/AVX2/NEON). Falls back to serde_json otherwise.
|
|
577
|
+
///
|
|
578
|
+
/// `simd_json::serde::from_slice` allocates fresh internal scratch buffers
|
|
579
|
+
/// (`Buffers::new`) on every call, sized proportionally to the input - measured
|
|
580
|
+
/// as the dominant cost, large enough to make the "simd" path consistently
|
|
581
|
+
/// SLOWER than plain serde_json (worse as input grows: -26% at 189 bytes,
|
|
582
|
+
/// -29% at 180KB). Reusing those buffers across calls via
|
|
583
|
+
/// `from_slice_with_buffers` (thread-local, since JValue's Rc-based design is
|
|
584
|
+
/// already single-threaded per instance) eliminates that reallocation and
|
|
585
|
+
/// brings simd-json back to consistently faster than serde_json (+5% to +22%
|
|
586
|
+
/// across the same size range, measured with benches/examples/simd_json_bench.rs).
|
|
577
587
|
pub fn from_json_str(s: &str) -> Result<JValue, serde_json::Error> {
|
|
578
588
|
#[cfg(feature = "simd")]
|
|
579
589
|
{
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
590
|
+
thread_local! {
|
|
591
|
+
static SCRATCH: std::cell::RefCell<(Vec<u8>, simd_json::Buffers)> =
|
|
592
|
+
std::cell::RefCell::new((Vec::new(), simd_json::Buffers::new(0)));
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
let result = SCRATCH.with(|scratch| {
|
|
596
|
+
let (bytes, buffers) = &mut *scratch.borrow_mut();
|
|
597
|
+
bytes.clear();
|
|
598
|
+
bytes.extend_from_slice(s.as_bytes());
|
|
599
|
+
simd_json::serde::from_slice_with_buffers::<JValue>(bytes, buffers)
|
|
600
|
+
});
|
|
601
|
+
if let Ok(value) = result {
|
|
583
602
|
return Ok(value);
|
|
584
603
|
}
|
|
585
604
|
// Fall back to serde_json if simd-json fails (e.g., unsupported CPU)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|