Repository navigation
Conversation
Quest-Claim: f7589f7b711c512c
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… in, and pass as slices to std's other functions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eir elements' type Constants, defaults, Option::as_slice, a Cow's borrow, and the erased SliceOf and Ptr are runs too; to_vec reads runs as they are; a wrapped array is an element, not runs; and runs copied out and written back copy an element only as its type says: a Copy object's copy, or objectCopy of one a write lands in, never a reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nitialized MaybeUninits, and joined slices of arrays Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…they are Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tive Rust Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Matches rs.ByteSlice and rs.RawSlice, as the maintainer decided at the round-3 design checkpoint. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Design change: after the round-3 checkpoint, the maintainer chose to continue with local fixes and to rename the type.
Rejected: merge as is; (Written by Claude Opus 5.5 with high effort) |
…s of arrays VecDeque's as_slices, as_mut_slices, and make_contiguous and BinaryHeap's as_slice of arrays lend an rs.ArraySlice of their own arrays, and a raw pointer to a slice of arrays is an rs.RawArraySlice of it, so Box::into_raw and from_raw give back the same storage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # ts/runtime/rs/collections.ts
…d a borrowed Cow, and split arrays lent lazily Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

Part 3 of quest/m3/ts-slice-object.md, after moq-dev/rust2#576 and moq-dev/rust2#584.
Problem
A slice of arrays had each array as a JS array of its own, so the arrays
as_chunks_mutandas_rchunks_mutlend from a flat slice had no JS array to be. They were aProxy(Runs,ByteRuns) whose elements werearrayViewproxies orsubarrayviews of each array, made and cached on first read, with detaching copies before a whole write. In a micro-bench of the codec bench'spacketsworkload, that cost 10-20x reading each array where the flat buffer holds it.Approach
rs.ArraySlice<S>, is every&[[T; N]],&mut [[T; N]],&[[T; N]; M], andBox<[[T; N]]>. Elementiis the slice of arrayi: anrs.Slice<T>, anrs.ByteSlicefor bytes, or anrs.ArraySlicefor arrays of arrays. It reads and writes arrayiwhere it is, whether each array is a JS array of its own (itemsand theofthat lends one, as aVec<[T; N]>or[[T; N]; M]holds them) ornelements of one flat slice (asas_chunkssplits it). NoProxy.iter/iter_mut,split_at_mut,chunks_mut,windows,split*,first_chunk*,swap, ...) map to the runtime'sarraySlice*functions (ts/src/lower/array_slice.rs'snative). Any other std function given a shared slice of arrays readsrs.arraySliceAsSlice: the arrays themselves, so a callback'sptr::eqsees the array it was lent, or copies of thoseas_chunkssplit from one flat slice, which have no JS array of their own. A&mutone readsrs.arraySliceBy's copies, written back once it returns, as Rust moves their elements. A function that would return a borrow of those copies is refused with a span.as_chunks/as_rchunks(shared and mutable) andslice::from_mut/array::from_mutof a&mut [T; N]lend anrs.ArraySliceof the same storage.Cell::from_mutof an array of arrays isrs.cellOfArraySlice.mem::replace/mem::swapof an array,clone_fromof arrays of arrays and of aBox<[[T; N]]>, raw pointers to arrays of arrays, andDebugof their iterators all go through it.rs.arraySliceBy,rs.arraySliceReplace,rs.arraySliceSwap,rs.cellOfArraySlice) copies its elements by the element type (copy::elem_copy): the type's copy shim where JS keeps aCopyvalue as an object,rs.objectCopywhere a write lands inside the object, or none. So the copy shares no object with the arrays it was read from, and a&Cellthat does share one is untouched.rs.ArraySlicetoo: constants andDefault,Option::as_slice/as_mut_sliceof an array payload (rs.optionAsArraySlice),Cow<[[T; N]]>(rs.Cow<T, rs.ArraySlice<S>>, borrowed byrs.cowArraySlice),assume_init_ref/assume_init_mutofMaybeUninitarrays andBox::assume_init(rs.arraySliceOfSlice), generic structs at an array instance, andconcat/joinparts and separators.joinlends an array separator as it is, since it clones it anyway, so each element'sClonereads the separator's own.Runs/ByteRunsproxies andView.detachare gone.arrayViewremains only where a&mut [T; N]into part of an array is taken whole as a JS array; that remainder is now the whole quest.Impact
rs.ArraySlicerather than anrs.Slice<T[]>/rs.Slice<Uint8Array>. Pass one asrs.arraySliceFrom(arrays, rs.sliceFrom)(rs.byteSliceFromfor bytes,rs.arraySliceOf(rs.sliceFrom)for arrays of arrays) and read one asrs.arraySliceItems(slice).ts/README.mddocuments it.ArraySlice,ArrayRef,LentArray,arraySlice*(arraySliceFrom,arraySliceOf,arraySliceAt,arraySliceItems,arraySliceAsSlice,arraySliceBy,arraySliceSet,arraySliceReplace,arraySliceSwap,arraySliceIter,arraySliceSplit*,arraySliceChunks*,arraySliceWindows, ...),cellOfArraySlice,arraySliceBoxCloneFrom,arraySliceBoxCloneFromFn,arraySliceCopy,ElemCopy,optionAsArraySlice,arraySliceOfSlice, andcowArraySlice.rs.Cowtakes a second type parameter, its borrowed form,rs.Slice<T>by default.arraySliceSwap,arraySliceBy, andarraySliceReplacetake the element copy as an argument. RemovedbyteSliceAsChunks,byteSliceAsChunksMut,byteSliceAsRchunks,byteSliceAsRchunksMut,sliceAsChunksMut, andsliceAsRchunksMut.sliceAsChunks/sliceAsRchunksnow returnrs.ArraySlice.Decisions
Decided with the maintainer on 2026-11-06:
&mut [[T; N]]holds its arrays: ✅ (a) a runtime slice-of-arrays type for every slice of arrays, nested or flat, which replaces theRuns/ByteRunsproxies (rejected: (b) eagersubarrayviews for bytes only, keeping theProxyfor other elements; (c) keep the proxies and drop the item). The quest narrows to it and is sized [L].slice::from_mut/array::from_mutof a&mut u8: ✅ kept, deferred to its own quest at the end of m3, quest/m3/ts-byte-slice-place.md (rejected: drop it until a consumer appears).*const [T]of values JS copies: ✅ moved into quest/m3/ts-runtime-throws.md with the form_urlencoded 1.2.2debug_assert!(ptr::eq(..))finding (rejected: wait on rs.String's UTF-8 route).Decided with the maintainer on 2026-11-07, at the round-3 design checkpoint (two medium findings, both conversions that copied arrays where Rust borrows them):
rs.ArraySliceonly for whatas_chunkssplits, keepingrs.Slice<T[]>for other slices of arrays; drop). Where each array is a JS array of its own,rs.arraySliceItemsslices the list of them instead of copying each, so arrays keep their identity for std callbacks such asbinary_search_byand forptr::eq.joinreads its separator without copying it. The arraysas_chunkssplits from one flat buffer have none of their own, so a callback still gets a copy; thatptr::eqgap is recorded in quest/m3/ts-runtime-throws.md.rs.Runstors.ArraySlice, matchingrs.ByteSliceandrs.RawSlice, with its helpersrs.arraySlice*(rejected:rs.Slices,rs.Chunks, keeprs.Runs).The quest file keeps only the
arrayViewremainder, sized [M].Choices made without asking:
array_slice::giveconverts a slice of arrays for every std function that isn't a trait's method, not just[T]'s own methods, soVec::extend_from_slice(&[[T; N]])and the like get the slice they read.rs.sliceToArray(an earlier head) also copied arrays a&Cellshares, which Rust doesn't.rs.sliceItemskeeps one signature forrs.Slice, and the translator emitsrs.arraySliceItemsfor an array slice. An overload maders.sliceItemslose its type when passed as a function, asOption::copiedpasses it.rs.ArraySlicelends each array as isrs.ArrayRef(wasRun), the array it lendsrs.LentArray(wasRunArray;rs.ArrayOfwas taken), the element copyrs.ElemCopy(wasRunCopy), and the oldrunsArray/runsItemsarearraySliceItems/arraySliceAsSlice, aftersliceItemsandas_slice. The translator's module islower/array_slice.rs.Bench
Rerunning at the new head; the numbers below are from 2c7ae6f.
bench/main.tsat 2c7ae6f,mainrouted to the merge base 324a7b7's translation (.tmp/bench.shundernix develop .#bench). Nanoseconds per packet, median ± half the IQR:packets/ts/numbermain → PRpackets/ts/number-copymain → PRValidation
just ciat b2a9375: passes (fixtures 89/89, including the lang fixtures' differential tests against native Rust).slices::array_formscovers each form above;slices::array_identitypins a callback'sptr::eqon a lent array (of bytes, words, and arrays, of all of a slice and of part of it) andjoin's separatorClonereading its own address. Each fails against native Rust with its fix reverted (74 and 79 differences).Alternatives
subarrayviews (decision 1b): 3-4x the flat form, and it keeps theProxyfor other element types.rs.Sliceper array made eagerly: allocates every array's slice up front;rs.ArraySlicemakes one only when it is read.Follow-ups
arrayViewremainder) and quest/m3/ts-byte-slice-place.md, both in this PR.Models
Size: L
Implementer: Claude Code, claude-opus-5-5, unknown effort
Implementer: Claude Code, claude-opus-5-5, high effort
Review
Rewritten by
quest reviewafter each round. A new session starts after the round-3 design checkpoint.🤖 Generated with Claude Code