Skip to content

feat(ts): translate cmp::max and min, is_sorted, and BinaryHeap - #252

Merged
kixelated merged 9 commits into
mainfrom
quest/m3/ts-ordering
Oct 30, 2026
Merged

kixelated merged 9 commits into
mainfrom
quest/m3/ts-ordering

Conversation

@kixelated

@kixelated kixelated commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Completes quest/m3/ts-ordering.md (removed here).

Problem

rust2-ts refused cmp::max and cmp::min (and their _by, _by_key forms), the is_sorted family, and BinaryHeap. Consumer: moq's census, where moq-net calls is_sorted_by_key (ietf/object.rs:219) and its dependencies rangemap and uuid call cmp::max/min. The quest also asked whether #173's comparison tests cost integers anything.

Approach

  • cmp::max, min, and their forms lower from std's MIR: each is one call into Ord::max/min or the closure, which already translate with std's drops. std_refused now allows &mut of a function, as FnMut calls take, since its writes are its own body's.
  • is_sorted: a slice's maps to rt.sliceIsSorted, a port of std's chunked loop (non-short-circuit within each 33-element chunk); the rest map to rt.iterIsSortedBy, std's next then all, dropping each item, the comparator, the last item, and the iterator in std's order.
  • BinaryHeap and PeekMut map to the runtime (rt.BinaryHeap, { d: T[] }), with std's sift_up, sift_down_range, sift_down_to_bottom, and rebuild_tail ported test for test, so which of equal keys pops first, into_sorted_vec, append, extend, and retain compare as std's do. Runtime, not std's MIR, because std's Hole moves elements through raw pointers into the Vec's storage. PeekMut's DerefMut hides the tail as std's set_len(1) does, so a forgotten guard leaves the heap as std's.
  • Integer comparison tests pass rt.lt/le/gt/ge instead of rt.cmpLt(rt.cmp).

Proven by a new orders case in the lang differential harness: an Item that logs every cmp/lt/le/gt/ge and drop, over max/min, is_sorted* (slices, iterators, owned and borrowed comparators and key functions), heaps driven by op bytes (push, pop, peek_mut writes, forgotten guards, PeekMut::pop, append, retain, extend, into_sorted_vec, drain, collect, into_iter), and heaps of bytes, Reverse, strings, and tuples. Mutations of a sift test, the comparator drop order, the PeekMut hide, and the rt.lent wrap give 45,867, 58, 2, and 69 differences.

#173's comparison tests on integers

New order/* bench workloads (sort, sort_by_key, iter max/min, Ord max/min fold, BinaryHeap), ns per item. pre173 is the commit before #173, built from its own tree; its heap route is not comparable (it predates BinaryHeap).

workload Chrome: cmpLt / direct / pre173 Firefox: cmpLt / direct / pre173
sort 97.8 / 94.5 / 102-108 155 / 124 / 141-172
sort-by-key 100 / 100 / 101-142 266 / 228 / 228-257
iter max/min 26.3 / 26.9 / 25.3-29.3 43.9 / 35.7 / 34.3-39.7
Ord max/min 21.9 / 24.2 / 22.7-24.8 35.1 / 38 / 34.1-43.6
binary-heap 58.9 / 38.7 / n/a 181 / 135 / n/a

The cost showed in Firefox (0.8-0.86x the time with direct tests on sort and max/min) and on the heap in Chrome (0.66x); V8 elsewhere is within noise. So the direct tests landed.

Impact

  • Translator output: these calls now translate instead of refusing. Census (pinned moq): moq-net refusals 1607 -> 1592, model 537 -> 525, kio unchanged, no new refusals.
  • Runtime (internal to generated code, not a breaking change): adds rt.le, rt.gt, rt.ge, rt.sliceIsSorted, rt.iterIsSortedBy, rt.BinaryHeap, rt.PeekMut, and the heap*/peekMut* functions. ts/MIGRATE.md's example updated to show rt.iterMax(it, rt.lt) for integers.
  • called_closures no longer spends an Fn/FnMut closure a mapping discards, so Iterator::is_sorted_by drops its comparator itself.

Alternatives

  • Lower BinaryHeap from std's MIR: blocked on raw-pointer Hole moves (ts-unsafe).
  • Keep rt.cmpLt(rt.cmp) for integers: simpler output, but measurably slower in Firefox and on the heap.
  • Refuse mem::forget of a PeekMut: smaller, but the O(1) array swap matches std exactly.

Choices made without asking

  • Runtime mapping for BinaryHeap (above), and direct integer tests for every PartialOrd test, not only ordering's.
  • A forgotten PeekMut leaks the hidden tail as std's does.
  • The bench gained the order op and a hand-written route (bench/order.ts).

Follow-ups

  • quest/m3/ts-unsafe.md now plans replacing rt.BinaryHeap and rt.PeekMut with std's translated MIR once raw pointers translate, the orders case proving it still matches.
  • quest/m3/ts-slice-gaps.md: slice windows/chunks, Vec::drain, and byte arrays' order, each refused and rewritten around in this PR's fixtures and bench.

Review

quest review --base origin/main, codex gpt-6.1-sol medium, 4 rounds; round 4 on head e10ad42 reported no findings.

  • Round 1: forgotten PeekMut did not leak the tail (fixed, PeekMut hides it); is_sorted_by dropped an owning comparator after the last item (fixed, dropped by iterIsSortedBy).
  • Round 2: is_sorted_by_key(&key) over a dropping iterator dropped key (fixed, rt.lent).
  • Round 3: the same through Box::new(&key) (fixed, lent unless an owned function).

Skipped as trivial on head 6db3efd: since the reviewed head it adds a quest-only Plan bullet to quest/m3/ts-unsafe.md (replace rt.BinaryHeap/rt.PeekMut with std's MIR once raw pointers translate) and merges origin/main, whose fixture conflicts kept both sides' entries (harness cases, reject roots and functions) with generated snapshots regenerated. quest check and just ci pass on that head.

(written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 7 commits October 29, 2026 21:10
Quest-Claim: ae5726858cb8e8a0
`cmp::max`, `min`, and their `_by` and `_by_key` forms lower from std's MIR.
The `is_sorted` family of slices and iterators maps to runtime ports of std's
loops, and `BinaryHeap` with `PeekMut` to a runtime port of std's sifts.
Integer comparisons pass `rt.lt` and its siblings instead of a test built from
`cmp`, which the bench shows costs in Firefox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…parator first

`PeekMut`'s `DerefMut` hides the heap's tail behind a heap of the top alone,
as std's `set_len(1)` does, so a forgotten guard leaves the heap as std's.
`is_sorted_by` drops its comparator before the last item and the iterator,
as std's `all` does, which also lets an iterator that drops take one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`is_sorted_by_key(&f)` over an iterator that drops disposed the map holding
`f`, which dropped what `f` owns before its owner did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	ts/fixtures/lang/expected/harness.ts
# Conflicts:
#	ts/fixtures/lang/expected/harness.ts
#	ts/fixtures/lang/src/harness.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Ordering in std feat(ts): translate cmp::max and min, is_sorted, and BinaryHeap Oct 30, 2026
@kixelated
kixelated marked this pull request as ready for review October 30, 2026 05:53
@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 34 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 15756253-28e1-4568-ba78-dba9b4d3850a
Commits

Reviewing files that changed from the base of the PR and between 7edb4e5 and 6db3efd.

Files selected for processing: 43
  • quest/m3/README.md
  • quest/m3/ts-ordering.md
  • quest/m3/ts-slice-gaps.md
  • quest/m3/ts-unsafe.md
  • ts/MIGRATE.md
  • ts/README.md
  • ts/bench/moq.ts
  • ts/bench/order.ts
  • ts/bench/workloads.ts
  • ts/fixtures/codec/expected/bench.ts
  • ts/fixtures/codec/src/bench.rs
  • ts/fixtures/lang/expected/collections.ts
  • ts/fixtures/lang/expected/core/cmp.ts
  • ts/fixtures/lang/expected/core/option.ts
  • ts/fixtures/lang/expected/edits.ts
  • ts/fixtures/lang/expected/harness.ts
  • ts/fixtures/lang/expected/iters.ts
  • ts/fixtures/lang/expected/orders.Item.ts
  • ts/fixtures/lang/expected/orders.ts
  • ts/fixtures/lang/expected/refs.ts
  • ts/fixtures/lang/expected/wrappers.ts
  • ts/fixtures/lang/src/harness.rs
  • ts/fixtures/lang/src/lib.rs
  • ts/fixtures/lang/src/orders.rs
  • ts/fixtures/reject/census.md
  • ts/fixtures/reject/expected.txt
  • ts/fixtures/reject/src/lib.rs
  • ts/fixtures/reject/ts.toml
  • ts/fixtures/task/expected/drops.ts
  • ts/fixtures/task/expected/drops/closures.ts
  • ts/fixtures/task/expected/drops/folds.ts
  • ts/fixtures/task/expected/drops/iters.ts
  • ts/runtime/rt.ts
  • ts/runtime/rt/collections.ts
  • ts/runtime/rt/int.ts
  • ts/runtime/rt/iter.ts
  • ts/src/lower/collections.rs
  • ts/src/lower/drop.rs
  • ts/src/lower/fmt.rs
  • ts/src/lower/iter.rs
  • ts/src/lower/library.rs
  • ts/src/lower/mir/mod.rs
  • ts/src/lower/mod.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit e10ad42da3d1e00ef7d58bca91f2c1f73f6756c3.

No actionable bugs found in this static review. The ordering mappings preserve custom comparison hooks rather than replacing them with a generic comparison; direct tests are limited to numeric integer/char representations. The sorted-iterator helper explicitly orders item and comparator drops, and borrowed key closures remain lent. Independent inspection of BinaryHeap/PeekMut found the saved-tail handling consistent across repeated mutable dereferences, forgotten guards, drop and pop. The differential fixture exercises comparison/drop traces as well as equal keys and whole-value replacement.

Direction: using std MIR for max/min and small runtime mappings where raw-pointer heap internals cannot translate is a reasonable split. Keep the direct integer path separate from custom PartialOrd behavior. The benchmark and census numbers in the description remain author-reported evidence, not independently verified results.

Verification limits: GitHub-only inspection of lowering, runtime code and Rust/generated fixtures, including an independent heap/ownership pass. I did not run translation, differential tests, mutation checks or benchmarks.

(Written by OpenAI)

kixelated and others added 2 commits October 29, 2026 23:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	quest/m3/ts-unsafe.md
#	ts/fixtures/lang/expected/harness.ts
#	ts/fixtures/lang/src/harness.rs
#	ts/fixtures/reject/census.md
#	ts/fixtures/reject/expected.txt
#	ts/fixtures/reject/src/lib.rs
#	ts/fixtures/reject/ts.toml
@kixelated
kixelated merged commit cff3177 into main Oct 30, 2026
2 checks passed
@kixelated
kixelated deleted the quest/m3/ts-ordering branch October 30, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant