Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
49ce902
chore(quest): claim quest/m3/ts-iter-back-folds.md
kixelated Nov 2, 2026
539823c
feat(ts): translate rfold and try_rfold, and a crate's own folds, nth…
kixelated Nov 3, 2026
20a14e2
Merge remote-tracking branch 'origin/main' into quest/m3/ts-iter-back…
kixelated Nov 3, 2026
b46c2f8
style(ts): format
kixelated Nov 3, 2026
6428d1c
fix(ts): keep Poll verbatim in the census
kixelated Nov 3, 2026
61ea38d
docs(ts): note rt.iterFrom's Own record in MIGRATE
kixelated Nov 3, 2026
8505cee
fix(ts): lend a fold's closure to the crate's own fold, and refuse fo…
kixelated Nov 3, 2026
f718af8
fix(ts): check the closures in a crate's own fold, and refuse its dro…
kixelated Nov 3, 2026
87285d7
style(ts): format
kixelated Nov 3, 2026
6c6d137
fix(ts): refuse a crate's own fold that tells its accumulator or clos…
kixelated Nov 3, 2026
3d36f72
test(ts): refresh the reject census
kixelated Nov 3, 2026
18c1b43
Merge origin/main into quest/m3/ts-iter-back-folds
kixelated Nov 3, 2026
28042e3
Merge origin/main into quest/m3/ts-iter-back-folds
kixelated Nov 3, 2026
f1e9b4c
fix(ts): read a boxed crate iterator by std's box, which forwards onl…
kixelated Nov 3, 2026
a9194ba
Merge origin/main into quest/m3/ts-iter-back-folds
kixelated Nov 3, 2026
c064c0b
fix(ts): read a boxed iterator as std's box does, by next where it fo…
kixelated Nov 3, 2026
9f62071
Merge origin/main into quest/m3/ts-iter-back-folds
kixelated Nov 3, 2026
afe5a21
test(ts): dyns' borrowed boxes read as rt.iterBoxed
kixelated Nov 3, 2026
9f0a80c
Merge origin/main into quest/m3/ts-iter-back-folds
kixelated Nov 3, 2026
de8f40a
Merge base into pr-463, retaining both migration notes
Nov 3, 2026
627bc41
Merge origin/main into quest/m3/ts-iter-back-folds
kixelated Nov 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ generic std gap is planned here even when moq never calls it.
- [std's calls of a closure that have no mapping](/quest/m3/ts-closure-calls.md) - `try_fold`, `partition`, `repeat_with`, `sort_by_cached_key`, and `LazyCell::new` translate, dropping what their closures own as std's do
- [Waiting: a slice object for a mutable part of other values](/quest/m3/ts-slice-object.md) - waits on a moq profile showing the `Proxy` view's traps matter, then decides on an `rt.ByteSlice`-like form
- [Port the workflow guard to kixelated/quest](/quest/m3/quest-workflow-guard.md) - quest's environment guard parses YAML as this repository's does
- [Folds from the back, and a crate's own folds](/quest/m3/ts-iter-back-folds.md) - `rfold` and `try_rfold` translate, and so does a crate's iterator that overrides `fold` or `nth_back`
- [A crate's own find and for_each](/quest/m3/ts-iter-own-calls.md) - a crate's iterator that overrides `find`, `rfind`, `find_map`, or `for_each` translates, each called where std's adaptors and consumers call it
- [A vector's exact capacity as it shrinks](/quest/m3/ts-vec-exact-capacity.md) - a deque made from a `Vec` splits its slices where std's does
- [A B-tree's searches call Ord as std's do](/quest/m3/ts-btree-search-order.md) - a B-tree's lookups and inserts call a key's own `Ord` in std's order and number
- [Rc and Arc of a slice](/quest/m3/ts-shared-slices.md) - `Rc<[T]>` and `Arc<[T]>` from a `Vec`, a slice, or an iterator translate
Expand Down
5 changes: 2 additions & 3 deletions quest/m3/ts-closure-calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ Found probing std's consumers for [drop order](/quest/m3/ts-drop-order.md) in
[#438](https://github.com/moq-dev/rust2/pull/438). Of a closure that owns nothing, each of
these is refused today:

- `Iterator::try_fold`, `try_for_each`, and `partition`. Folds from the back, `rfold` and
`try_rfold`, are [#436](https://github.com/moq-dev/rust2/pull/436)'s
[`ts-iter-back-folds`](https://github.com/moq-dev/rust2/blob/quest/m2/ts-model/iter-traits/quest/m3/ts-iter-back-folds.md).
- `Iterator::try_fold`, `try_for_each`, and `partition`. `rt.iterTryRfold` already folds
from the back as `try_rfold` does, breaking by an `Option`, `Result`, or `ControlFlow`.
- `iter::repeat_with`, and `Iterator::scan` of a state JS copies, which is refused as a
`&mut` its mapping would copy.
- `slice::sort_by_cached_key`.
Expand Down
30 changes: 0 additions & 30 deletions quest/m3/ts-iter-back-folds.md

This file was deleted.

32 changes: 32 additions & 0 deletions quest/m3/ts-iter-own-calls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# [M] A crate's own find and for_each

## Goal

[rust2-ts](/ts/README.md) translates a crate's own iterator that overrides a provided
method std's adaptors and consumers call on it other than those `rt.iterFrom` already
calls (`size_hint`, `next_back`, `len`, `nth`, `nth_back`, `fold`, `rfold`, `count`, and
`last`), such as `find`, `rfind`, `find_map`, or `for_each`. Each runs where native's does,
as many times and in the same order, proven by differential tests against native Rust.

## Plan

Left by the PR that finished folds from the back. Each is refused today as "overriding
`_`, which std's adaptors call in place of `next` or beside it":

- `Filter::next` and `SkipWhile::next` call their iterator's `find`, `FilterMap::next` its
`find_map`, and `Fuse`, `Chain`, and `Rev` forward `find` and `rfind`. The runtime's
adaptors read their iterator by `next` there, which is the same for std's own iterators
but skips a crate's override.
- `for_each` is what std's `Extend` impls for hash maps, `String`, and others call of the
iterator they are given.
- Each takes a closure, as `fold` does: the crate's `fold` translates for one
`Box<dyn FnMut>` accumulator-agnostic instance, which these could share.
- Overrides std never calls in place of another, such as `max` or `position`, only matter
where the crate calls them directly. Check which std calls each before lifting its
refusal.
- `try_fold`, `try_rfold`, `advance_by`, and `advance_back_by` can be overridden only on
nightly, through unstable traits and features.
- `lang`'s `ends` fixture's `Overrides` iterator logs each method it is called through, and
can extend to these.

Public API: the translator's output.
3 changes: 3 additions & 0 deletions ts/MIGRATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- `rt.iterFrom` takes `hint`, `back`, and `len` in one `rt.Own` record after `drop`,
which also holds the crate's own `nth`, `fold`, and the rest, as in
`rt.iterFrom(source, next, drop, { hint, back, len })`.
- In its type's module, the suffix of a method of a generic type behind a reference spells
the references after the type's arguments: `&mut Take<Bytes>`'s `Buf::chunk` is
`chunk$bytes_Buf_bytes_Bytes_mut`, not `chunk$bytes_Buf_mut_bytes_Bytes`, which is
Expand Down
12 changes: 9 additions & 3 deletions ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ compare the best and then the next, and a B-tree's iterators read their ends. `e
An iterator over a slice, array, or `Vec`, or a small range, that only its `next` and
moves read steps in place, as two variables: the array and an index into it, or the
range's bounds, with no `rt.Iter` made. The crate's own `impl Iterator` returns `rt.DONE` from its `next` too, and joins
std's adaptors through `rt.iterFrom`, which calls its own `size_hint`, `next_back`, and `len` where std's adaptors
std's adaptors through `rt.iterFrom`, which calls its own `size_hint`, `next_back`, `len`, `nth`, and `nth_back`,
and of one it owns its own `fold`, `rfold`, `count`, and `last`, where std's adaptors
call them, and `fuse` reads on past the end of one that is a `FusedIterator`, as std's does. A caller calls `next()` for one item, or iterates
an `rt.Iter` with `for ... of`. Each `rt.Iter`'s `sizeHint` is std's `size_hint`, its upper
bound `undefined` for `None`, and a `collect` or `extend` into a `Vec`, `VecDeque`,
Expand Down Expand Up @@ -457,7 +458,9 @@ drop it where std's do. So do iterators: one that owns its items, as a `Vec`'s `
map's `drain` does, drops those it still holds by `[Symbol.dispose]`, an adaptor drops
what it skips or rejects, and a consumer that takes an iterator by value drops it:
through each `rt.Iter`'s own `fold` where std's folds, which drops each adaptor's closure
as its fold ends, before what it wraps, as std's does. A `Vec`'s `drain` leaves the vector
as its fold ends, before what it wraps, as std's does. The crate's own `fold` is given that
closure as a `Box<dyn FnMut>`, which drops it where its body does. A `try_rfold` drops its
closure as it returns, leaving what the iterator holds to drop with it. A `Vec`'s `drain` leaves the vector
what precedes its range until it drops, then drops what it still holds and moves the tail
back, so one never dropped, as `mem::forget` leaves it, leaks the rest, as std's does.

Expand Down Expand Up @@ -916,7 +919,10 @@ copies that std makes, other than a map's, or hands a closure, as `iter_mut` and
`and_modify` do, one into a `Result`'s payload passed on or kept, the adaptors
without a mapping in `src/lower/iter.rs` (such as `partition`), an
own `impl Iterator` or `DoubleEndedIterator` that overrides a provided method other than
`size_hint` and `len`, such as `fold` or `nth_back`,
those, such as `find` or `for_each`, or whose own `fold` or `rfold` tells its accumulator or
closure apart from another, by an `Option` or a `Poll` of it, a call or constant generic over it
other than calling or dropping the closure or passing them to std's iterators outside the crate's
own types, or a drop of the accumulator,
a pointer's address (`{:p}`), `write!` with a placeholder into
the crate's own `fmt::Write`, a `str` pattern other than a
`char`, a `&str`, a predicate, or chars, a mutable `str` slice, a copy of a closure that changes
Expand Down
2 changes: 1 addition & 1 deletion ts/fixtures/crates/expected/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function run(input: rt.ByteSlice): rt.ByteVec {
}
rt.byteVecPush(out, _143);
}
const _151: rt.Iter<rt.u8> = rt.iterRev(rt.iterFrom(Countdown.new(rt.min(input.length, 5) & 0xff), (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), undefined, undefined, (it: Countdown.Countdown) => rt.iterFromOption(Countdown.nextBack$iter_DoubleEndedIterator(it))));
const _151: rt.Iter<rt.u8> = rt.iterRev(rt.iterFrom(Countdown.new(rt.min(input.length, 5) & 0xff), Countdown.next$iter_Iterator, undefined, { back: (it: Countdown.Countdown) => rt.iterFromOption(Countdown.nextBack$iter_DoubleEndedIterator(it)) }));
rt.iterExtendBytes(out, _151, "next");
const both: Countdown.Countdown = Countdown.new(rt.min(input.length, 6) & 0xff);
while (true) {
Expand Down
7 changes: 3 additions & 4 deletions ts/fixtures/lang/clones/expected/clones.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6602,7 +6602,6 @@ export function turns$vec_IntoIter_u8_clones_iters_closure18_clones_iters_closur
export function iters(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void {
let _263!: [rt.ByteSlice, rt.ByteSlice];
let _269!: rt.usize;
let it!: rt.Peekable<rt.u8>;
const plan: Plan.Plan = { dataData: data.data, dataStart: data.start, dataLen: data.length, at: kind as rt.usize };
const n: rt.usize = option_mapOr$1surhce(rt.byteSliceFirst(data), 1, (_2: rt.u8): rt.u8 => {
return rt.u8Add(rt.u8Rem(_2, 4), 1);
Expand Down Expand Up @@ -6893,7 +6892,7 @@ export function iters(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void {
}, plan, (x35: rt.u8): rt.u8 => {
return x35;
}, out);
turns$iter_Map_clones_Countdown_clones_iters_closure100_clones_iters_closure101_clones_iters_closure102(rt.iterMap(rt.iterFrom({ _0: rt.u8Mul(n & 0xff, 3) }, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it)), (x36: rt.u8): rt.u8 => {
turns$iter_Map_clones_Countdown_clones_iters_closure100_clones_iters_closure101_clones_iters_closure102(rt.iterMap(rt.iterFrom({ _0: rt.u8Mul(n & 0xff, 3) }, Countdown.next$iter_Iterator), (x36: rt.u8): rt.u8 => {
return x36 ^ 7;
}), (it33: rt.Iter<rt.u8>): rt.u8 | undefined => {
return rt.iterToOption(it33.next());
Expand All @@ -6902,7 +6901,7 @@ export function iters(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void {
}, out);
const _236: Countdown.Countdown = { _0: rt.u8Mul(n & 0xff, 3) };
const _240: rt.Iter<rt.u8> = rt.iterSlice(rt.byteSliceView(data));
turns$iter_Zip_clones_Countdown_slice_Iter_u8_clones_iters_closure103_clones_iters_closure104(rt.iterZip(rt.iterFrom(_236, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it)), _240), (it34: rt.Iter<[rt.u8, rt.u8]>): [rt.u8, rt.u8] | undefined => {
turns$iter_Zip_clones_Countdown_slice_Iter_u8_clones_iters_closure103_clones_iters_closure104(rt.iterZip(rt.iterFrom(_236, Countdown.next$iter_Iterator), _240), (it34: rt.Iter<[rt.u8, rt.u8]>): [rt.u8, rt.u8] | undefined => {
return rt.iterToOption(it34.next());
}, plan, (_261: [rt.u8, rt.u8]): rt.u8 => {
return _261[0] ^ _261[1];
Expand Down Expand Up @@ -7007,7 +7006,7 @@ export function iters(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void {
}), undefined, true);
rt.iterExtendBytes(out, rt.byteVecIntoIter(rt.refCellReplace(log, new rt.ByteVec())), undefined, true);
} else if (_9 === 8) {
it = rt.iterPeekable(rt.iterSlice(rt.byteSliceView(data)));
const it: rt.Peekable<rt.u8> = rt.iterPeekable(rt.iterSlice(rt.byteSliceView(data)));
let iterStart5: rt.usize = 0;
const iterEnd5: rt.usize = n;
while (iterStart5++ < iterEnd5) {
Expand Down
2 changes: 1 addition & 1 deletion ts/fixtures/lang/cycles/expected/cycles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function flush(log: rt.RefCell<rt.ByteVec>, out: rt.ByteVec): void {
*/
export function read$cycles_Countdown_cycles_cycles_closure4(it: Countdown.Countdown, steps: rt.ByteSlice, put: (a0: rt.u8) => rt.u8, out: rt.ByteVec): void {
let item!: rt.u8 | undefined;
const it2: rt.Iter<rt.u8> = rt.iterCycle(rt.iterFrom(it, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it)), { v: Countdown.clone$Clone });
const it2: rt.Iter<rt.u8> = rt.iterCycle(rt.iterFrom(it, Countdown.next$iter_Iterator), { v: Countdown.clone$Clone });
const _8: [rt.usize, rt.usize | undefined] = it2.sizeHint();
const lower: rt.usize = _8[0];
rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(lower & 0xff, (lower >>> 24) & 0xff, option_mapOr$02k4ito(_8[1], 254, (n2: rt.usize): rt.u8 => {
Expand Down
Loading