Repository navigation
Add RawValue::from_string_unchecked - #1331
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dtolnay
left a comment
There was a problem hiding this comment.
Thanks, this looks reasonable.
The "single well-formed JSON value" requirement makes sense but the "no leading or trailing whitespace" requirement might be a bit subtle. I expect many prospective callers might not realize if they have a trailing newline, such as a value coming from an include_str! where most text editors will fight you from trying to save the file without a trailing newline.
I think we should consider one of:
- Trim whitespace without validating JSON. This is O(1) in the common case of 0 leading whitespace and 0–1 trailing whitespace.
- Debug-assert the whitespace requirement.
- Debug-assert both requirements.
Per review, the "no leading or trailing whitespace" clause of the safety contract is easy to violate accidentally (e.g. a trailing newline from include_str!). Adding a debug_assert! that re-parses the input and checks the borrowed slice length catches both requirements at once, and compiles out in release so the "no re-parse" property still holds.
|
Thanks for the quick review! I went with your third suggestion — a Why not option 1 (trim in the library):
Why not option 2 (debug-assert whitespace only): the well-formedness violation is the strictly more severe failure mode (it corrupts the enclosing document, not just adds spaces), so checking only whitespace felt inverted. Doing both is essentially free — the parser walks the input once. Two |
|
Published in 1.0.151. |
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [displaydoc](https://github.com/yaahc/displaydoc) | dependencies | patch | `0.2.6` → `0.2.7` | | [hybrid-array](https://github.com/RustCrypto/hybrid-array) | dependencies | patch | `0.4.13` → `0.4.14` | | [regex](https://github.com/rust-lang/regex) | dev-dependencies | patch | `1.13.0` → `1.13.1` | | [serde](https://serde.rs) ([source](https://github.com/serde-rs/serde)) | dependencies | patch | `1.0.228` → `1.0.229` | | [serde_json](https://github.com/serde-rs/json) | dev-dependencies | patch | `1.0.150` → `1.0.151` | --- ### Release Notes <details> <summary>yaahc/displaydoc (displaydoc)</summary> ### [`v0.2.7`](https://github.com/yaahc/displaydoc/blob/HEAD/CHANGELOG.md#027---2026-07-28) [Compare Source](yaahc/displaydoc@v0.2.6...v0.2.7) #### Added - Updated `syn` dependency to 3.0 #### Changed - Bumped MSRV to 1.71 </details> <details> <summary>RustCrypto/hybrid-array (hybrid-array)</summary> ### [`v0.4.14`](https://github.com/RustCrypto/hybrid-array/blob/HEAD/CHANGELOG.md#0414-2026-07-30) [Compare Source](RustCrypto/hybrid-array@v0.4.13...v0.4.14) ##### Added - Sizes for `sntrup` ([#​231]) [#​231]: RustCrypto/hybrid-array#231 </details> <details> <summary>rust-lang/regex (regex)</summary> ### [`v1.13.1`](https://github.com/rust-lang/regex/blob/HEAD/CHANGELOG.md#1131-2026-07-15) [Compare Source](rust-lang/regex@1.13.0...1.13.1) \=================== This is a release that fixes a bug where incorrect regex match offsets could be reported. Note that this doesn't impact whether a match occurs or not, just where it occurs. The match offsets are still valid for slicing, they just may not refer to the correct leftmost-first match. See [#​1364](rust-lang/regex#1364) for (many) more details. Bug fixes: - [#​1354](rust-lang/regex#1354): Fixes previously unsound reverse suffix and inner optimizations. </details> <details> <summary>serde-rs/serde (serde)</summary> ### [`v1.0.229`](https://github.com/serde-rs/serde/releases/tag/v1.0.229) [Compare Source](serde-rs/serde@v1.0.228...v1.0.229) - Update to syn 3 </details> <details> <summary>serde-rs/json (serde_json)</summary> ### [`v1.0.151`](https://github.com/serde-rs/json/releases/tag/v1.0.151) [Compare Source](serde-rs/json@v1.0.150...v1.0.151) - Add RawValue::from\_string\_unchecked ([#​1331](serde-rs/json#1331), thanks [@​WonderLawrence](https://github.com/WonderLawrence)) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODEuMSIsInVwZGF0ZWRJblZlciI6IjQ0LjExLjYiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==--> Reviewed-on: https://dev.unebaguette.fr/vexahub/voprf-vx/pulls/16 Co-authored-by: Renovate Bot <renovatebot@lunomail.com>
Update patch dependencies This MR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [console_error_panic_hook](https://github.com/rustwasm/console_error_panic_hook) | workspace.dependencies | patch | `=0.1.5` → `=0.1.7` | | [godot](https://godot-rust.github.io) ([source](https://github.com/godot-rust/gdext)) | workspace.dependencies | patch | `=0.5.3` → `=0.5.5` | | [serde](https://serde.rs) ([source](https://github.com/serde-rs/serde)) | workspace.dependencies | patch | `=1.0.228` → `=1.0.229` | | [serde_json](https://github.com/serde-rs/json) | workspace.dependencies | patch | `=1.0.149` → `=1.0.151` | --- ### Release Notes <details> <summary>rustwasm/console_error_panic_hook (console_error_panic_hook)</summary> ### [`v0.1.6`](rustwasm/console_error_panic_hook@0.1.5...0.1.6) [Compare Source](rustwasm/console_error_panic_hook@0.1.5...0.1.6) </details> <details> <summary>godot-rust/gdext (godot)</summary> ### [`v0.5.5`](https://github.com/godot-rust/gdext/blob/HEAD/Changelog.md#v055) [Compare Source](godot-rust/gdext@v0.5.4...v0.5.5) *9 August 2026* ##### 🌻 Features - `EngineBitfield`: add `with()` and `without()` methods ([#​1627](godot-rust/gdext#1627)) - `#[func(virtual)]` now supports `async fn` for GDScript coroutines ([#​1645](godot-rust/gdext#1645)) - Add `PhantomData<T>` support for `GodotConvert` derive macro ([#​1619](godot-rust/gdext#1619)) ##### 📈 Performance - Singletons are now cached ([#​1636](godot-rust/gdext#1636)) - Cache user singleton pointers ([#​1644](godot-rust/gdext#1644)) - Cheaper refcount operations ([#​1669](godot-rust/gdext#1669)) ##### 🧹 Quality of life - Always use godot\_error in panic hook ([#​1647](godot-rust/gdext#1647)) - Rename `cast_int/cast_float` to `to_vector*/to_rect*` ([#​1661](godot-rust/gdext#1661)) - Validate class registrations against `ClassDB` ([#​1664](godot-rust/gdext#1664)) ##### 🛠️ Bugfixes - Fix `#[var(pub)]` panic during `OnEditor<Gd<T>>` reload ([#​1639](godot-rust/gdext#1639)) - Fix async `SignalFuture` panic when object is freed before exit flag ([#​1648](godot-rust/gdext#1648)) - Fix `api-custom` build when prebuilt lags detected Godot version ([#​1649](godot-rust/gdext#1649)) - Harden various parts of codebase ([#​1660](godot-rust/gdext#1660)) - Fix `GFile` `BufRead` past EOF ([#​1670](godot-rust/gdext#1670)) ##### 🏗️ Maintenance - Replace `godot-cell` borrow-state proptests with exhaustive model check ([#​1650](godot-rust/gdext#1650)) - Make accidental access of `#[doc(hidden)]` symbols more explicit ([#​1651](godot-rust/gdext#1651)) - Follow-up to rustc / Godot changes ([#​1659](godot-rust/gdext#1659)) - Name virtual-callback layers after user-facing `I*` virtuals ([#​1662](godot-rust/gdext#1662)) - Move ref-counting operations from `DynMemory` to `RawGd` ([#​1667](godot-rust/gdext#1667)) ### [`v0.5.4`](https://github.com/godot-rust/gdext/blob/HEAD/Changelog.md#v054) [Compare Source](godot-rust/gdext@v0.5.3...v0.5.4) *23 June 2026* ##### 🌻 Features - Godot 4.7: add `api-4-7` level ([#​1641](godot-rust/gdext#1641)) - Type-Safe API for User-defined RPCs ([#​1535](godot-rust/gdext#1535), [#​1634](godot-rust/gdext#1634)) - String conversions: ` to_gstring()`, `to_string_name()` etc ([#​1623](godot-rust/gdext#1623)) - Thread-safe FFI scaffolding + cross-thread printing ([#​1632](godot-rust/gdext#1632)) - `Gd` introspection APIs: `dynamic_class`, `is_dynamic_class[_of]`, `is_ref_counted` ([#​1631](godot-rust/gdext#1631)) - Support async versions of `tools::load()` and `tools::try_load()` ([#​1601](godot-rust/gdext#1601)) - Support `@export_node_path` attribute ([#​1620](godot-rust/gdext#1620)) ##### 🧹 Quality of life - Slightly more flexible `GodotStringExt` through unsized impls ([#​1629](godot-rust/gdext#1629)) - Suppress Godot errors in fallible functions ([#​1637](godot-rust/gdext#1637)) ##### 🛠️ Bugfixes - Fix Linux hot-reload panic when TLS destructors fire before init ([#​1611](godot-rust/gdext#1611)) - Fix panic-in-drop in future tests; harden against race conditions ([#​1617](godot-rust/gdext#1617)) - Auto-remove custom callables also when connected in untyped APIs ([#​1612](godot-rust/gdext#1612)) - Fix async panics at shutdown ([#​1625](godot-rust/gdext#1625)) - Fix `Object` returns with dynamic type `RefCounted` ([#​1628](godot-rust/gdext#1628)) - Fix memory leak for `connect_self()` on `RefCounted` ([#​1635](godot-rust/gdext#1635)) - Fix dangling singleton pointer after deinit ([#​1638](godot-rust/gdext#1638)) - Fix RPC borrow panic for `call_local` ([#​1643](godot-rust/gdext#1643)) ##### 🏗️ Maintenance - Add `once` flag to `defer_startup_warn!` and `defer_startup_error!` ([#​1613](godot-rust/gdext#1613)) - CI: unzip occasionally fails; retry ([#​1616](godot-rust/gdext#1616)) - Rename self-registration parts: `plugin` -> `shard` ([#​1618](godot-rust/gdext#1618)) - Replace internal `PassiveGd` with safer `BorrowedGd` ([#​1633](godot-rust/gdext#1633)) ##### 📚 Documentation - Document `register-docs` security; warn when used in export builds ([#​1615](godot-rust/gdext#1615)) - Document `#[class(tool)]` + `ready()` behavior across editor reload ([#​1614](godot-rust/gdext#1614)) - Fix borrow panic in `godot::task::spawn` doc example ([#​1622](godot-rust/gdext#1622)) </details> <details> <summary>serde-rs/serde (serde)</summary> ### [`v1.0.229`](https://github.com/serde-rs/serde/releases/tag/v1.0.229) [Compare Source](serde-rs/serde@v1.0.228...v1.0.229) - Update to syn 3 </details> <details> <summary>serde-rs/json (serde_json)</summary> ### [`v1.0.151`](https://github.com/serde-rs/json/releases/tag/v1.0.151) [Compare Source](serde-rs/json@v1.0.150...v1.0.151) - Add RawValue::from\_string\_unchecked ([#​1331](serde-rs/json#1331), thanks [@​WonderLawrence](https://github.com/WonderLawrence)) ### [`v1.0.150`](https://github.com/serde-rs/json/releases/tag/v1.0.150) [Compare Source](serde-rs/json@v1.0.149...v1.0.150) - Reject non-string enum object keys ([#​1324](serde-rs/json#1324), thanks [@​puneetdixit200](https://github.com/puneetdixit200)) </details> --- ### Configuration 📅 **Schedule**: (in timezone Asia/Taipei) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This MR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zMy4yIiwidXBkYXRlZEluVmVyIjoiNDQuMzMuMiIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> See merge request TW0hank0/positive_mahjong!142
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [serde_json](https://github.com/serde-rs/json) | dependencies | patch | `1.0.150` → `1.0.151` | --- ### Release Notes <details> <summary>serde-rs/json (serde_json)</summary> ### [`v1.0.151`](https://github.com/serde-rs/json/releases/tag/v1.0.151) [Compare Source](serde-rs/json@v1.0.150...v1.0.151) - Add RawValue::from\_string\_unchecked ([#​1331](serde-rs/json#1331), thanks [@​WonderLawrence](https://github.com/WonderLawrence)) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE3MS4xIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate <renovate@impure.systems> Co-authored-by: Luca Di Carlo <luca@noreply.git.impure.systems> Reviewed-on: https://git.impure.systems/luca/legifrss/pulls/18
Add
RawValue::from_string_uncheckedAn unchecked counterpart of
RawValue::from_string, for strings that are already known to be valid JSON — typically the output of another JSON serializer, or JSON that was validated once and cached.Motivation
RawValue::from_stringre-parses the entire input to establish the validity invariant. When the input is trusted by construction, that parse is pure overhead and becomes significant on hot paths that handle large payloads.Concrete case: JSON-RPC servers (Ethereum execution clients such as reth and its forks) serve multi-megabyte, hot-cached or SIMD-serialized results. The only public way to embed such a payload today is
from_string, whose validation scan claws back roughly a third of the serializer's gains — measured on x86_64/AVX2 for a 4 MB payload: serialize with sonic-rs 272 µs, thenfrom_stringvalidation 740 µs. jsonrpsee has the same redundant cost internally on every response it builds from its own serializer output (paritytech/jsonrpsee#1648).Design
Follows the
str::from_utf8/str::from_utf8_uncheckedprecedent: the checked API stays the default, and theunsafe fnopts out of validation with the contract documented under# Safety— other code (including unsafe code) is allowed to rely onRawValuecontaining well-formed JSON, in the same way unsafe code may rely onstrcontaining valid UTF-8.Additive, no behavior change for existing APIs, gated behind the existing
raw_valuefeature.