diff --git a/quest/m3/README.md b/quest/m3/README.md index d166fcf22..3cd92bbac 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -21,6 +21,7 @@ generic std gap is planned here even when moq never calls it. - [A trait object in a struct's last field](/quest/m3/ts-dyn-tail.md) - `Rc>` and the like translate, the last field as the object - [bytes' Chain as a Buf object](/quest/m3/ts-buf-chain.md) - `Chain::copy_to_bytes` across both halves translates, and with it a `Chain` as a `dyn Buf` - [A Buf object's size](/quest/m3/ts-dyn-buf-size.md) - a `dyn Buf` object holds only the methods some call dispatches to +- [A boxed iterator folds as std's box does](/quest/m3/ts-box-folds.md) - a `Box` reads by `next` where std's `Iterator` for `Box` forwards nothing else - [by_ref of a mutable reference to an iterator](/quest/m3/ts-by-ref-place.md) - `Iterator::by_ref` of a `&mut I` in a local translates - [mem::take as a function value](/quest/m3/ts-take-value.md) - `mem::take`, `replace`, and `swap` passed as a function value translate - [Debug of a RefCell](/quest/m3/ts-refcell-debug.md) - `{:?}` of a `RefCell`, `Ref`, and `RefMut` translates as std's writes them diff --git a/quest/m3/ts-box-folds.md b/quest/m3/ts-box-folds.md new file mode 100644 index 000000000..9d2bd5994 --- /dev/null +++ b/quest/m3/ts-box-folds.md @@ -0,0 +1,24 @@ +# [S] A boxed iterator folds as std's box does + +## Goal + +[rust2-ts](/ts/README.md) reads a `Box` of a sized iterator, owned or behind a `&mut`, +as std's `Iterator` for `Box` does: by `I`'s own `next`, `size_hint`, `nth`, `last`, +`next_back`, `nth_back`, `len`, and `is_empty`, and by `next` or `next_back` for every +other consumer, proven by the lang fixture's differential tests against native Rust. + +## Plan + +Found on 2026-11-03 probing what [#437](https://github.com/moq-dev/rust2/pull/437) left: +the translation erases the box and folds what it holds by its own `fold`, where std's +defaults read the box by `next`. A boxed `Chain` of mapped `vec::IntoIter`s matches native +across `count`, `fold`, `for_each`, `find`, `position`, `max_by_key`, `rev().fold`, and +`skip(1).count()`, since `Chain`'s folds read and drop in `next`'s order. A box of a `skip` +of a zip std reads by index does not: `Box::new(a.map(f).zip(b.map(g)).skip(1)).count()` +makes and drops the skipped pair whole, as `Skip`'s fold does, where native skips it a +side at a time through the zip's `nth`. + +`rt.iterDyn` already reads a `dyn Iterator` this way, so a box of a sized iterator can be +one too, with `last` forwarded to the iterator's own, as std's `BoxIter` specializes it. + +Public API: the translator's output.