fix(runtime): hydrate a tuple captured by a runtime expression - #255
Open
AmeinEskinder wants to merge 1 commit into
Open
fix(runtime): hydrate a tuple captured by a runtime expression#255AmeinEskinder wants to merge 1 commit into
AmeinEskinder wants to merge 1 commit into
Conversation
`expr.md` lists tuples in the shared vocabulary and `expr_field.rs` compiles `pair.0` to JavaScript `pair[0]`, so a tuple is an array on the browser side, and serde writes a tuple surrogate as one. `hydrateSurrogate` had no array case, so an array fell past the tag switch into the default arm and threw `Unknown surrogate type: undefined`. Every expression that captured a tuple failed to hydrate, and since `scan` walks the document in one loop with no `try`/`catch`, nothing after it hydrated either. Hydrate an array by hydrating its elements, checked before the tag because an array is an object with no `t`. It stays a real array so the generated `pair[0]` still indexes it. That alone would trade the throw for a quieter disagreement, so the two render paths follow the server as well. `NodeViewParts for (T1, T2)` writes its elements one after another with no separator, where `String(array)` would have inserted commas: `$(pair)` on `(1.5, 2.5)` renders `1.52.5` on both sides now, not `1.5,2.5` in the browser. `AttributeValueViewParts for (T1, T2)` is present when any element is and skips the ones that are not, the way a `None` writes nothing. Tests cover hydration, both render paths, and the wire format the fix depends on. Each one fails with its branch removed. Closes tokio-rs#254.
AmeinEskinder
force-pushed
the
fix/tuple-surrogate-hydration
branch
from
July 31, 2026 15:06
82a2d55 to
ae14e44
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #254.
expr.mdlists tuples in the shared vocabulary, andexpr_field.rs:21compilespair.0into JavaScriptpair[0], so a tuple is an array on the browser side. Serde writes a tuple surrogate as one.hydrateSurrogatehad no array case, so the array fell past the tag switch into the default arm and threw:Every expression capturing a tuple failed to hydrate, and
scanwalks the document in a single loop with notry/catch, so nothing after it hydrated either.The change
Hydrate an array by hydrating its elements. The check sits before the tag switch because an array is an object with no
t, and the result stays a real array so the generatedpair[0]still indexes it.That alone would trade a throw for a quieter disagreement, so both render paths follow the server too:
$(pair)on(1.5, 2.5)1.52.51.52.5:title=$(pair)on("a", "b")title="ab"title="ab"NoneNodeViewParts for (T1, T2)writes its elements one after another with no separator, whereString(array)would have given1.5,2.5.AttributeValueViewParts for (T1, T2)is present when any element is, and skips the ones that are not, the way aNonewrites nothing — callingtoAttributeValue()on aNonewould itself have thrown.Verification
The strings below are what
topcoat-runtimeactually rendered forlet pair = (1.5f64, 2.5f64), taken from a rendered view rather than written by hand:Running those exact strings through the patched runtime gives
1.5and1.52.5, matching the server's1.5and1.52.5. Both threw before.Eleven tests cover hydration, both render paths, and the wire format the fix depends on. I disabled each of the three new branches in turn and confirmed every test fails without it, with the failures being the divergences above (
a,bforab,1.5,2.5for1.52.5,a,[object Object],bfor a tuple holding aNone).The Rust-side tests pin the serialized shape (
[1.5,2.5],[1.0,{"t":"Option","v":2.0},true],[[1.0,2.0],3.0]) so a change to tuple serialization can't silently break the browser half.Checks
yarn build,yarn test(31 passed),cargo test -p topcoat-runtime,cargo clippy -p topcoat-runtime --all-targets(0 warnings),cargo fmt --check.dist/index.jsis rebuilt.