From 997294a2e6a6aee15917e1f8220e99d040e76cdd Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Mon, 2 Nov 2026 21:31:51 -0800 Subject: [PATCH 1/4] chore(quest): claim quest/m3/ts-box-folds.md Quest-Claim: c993241894bc93d0 From 408a0969cd90710fe803179558f6fd30e680b20a Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Mon, 2 Nov 2026 21:51:15 -0800 Subject: [PATCH 2/4] feat(ts): read a boxed iterator as std's Iterator for Box does A box of an iterator, a trait object or not, owned or behind a `&mut`, is rt.iterBox of it: it forwards next, size_hint, nth, last, and the double-ended and exact-size methods, and reads the rest by next, advance_by and the folds included, where the translation folded what the box held by its own folds. Co-Authored-By: Claude Opus 5.5 --- quest/m3/README.md | 1 - quest/m3/ts-box-folds.md | 24 -- ts/README.md | 7 +- ts/fixtures/lang/dyns/expected/core/option.ts | 14 + ts/fixtures/lang/dyns/expected/dyns.ts | 266 ++++++++++++++++-- ts/fixtures/lang/dyns/expected/lib.ts | 22 +- ts/fixtures/lang/dyns/src/dyns.rs | 123 ++++++++ ts/fixtures/lang/dyns/src/lib.rs | 1 + ts/runtime/rt/iter.ts | 40 ++- ts/src/lower/iter.rs | 45 ++- 10 files changed, 474 insertions(+), 69 deletions(-) delete mode 100644 quest/m3/ts-box-folds.md diff --git a/quest/m3/README.md b/quest/m3/README.md index 73b49b14e..848e6ce13 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -21,7 +21,6 @@ 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 - [Debug of a RefCell or a Cell](/quest/m3/ts-refcell-debug.md) - `{:?}` of a `RefCell`, `Ref`, `RefMut`, and `Cell` translates as std's writes them - [Placeholders written to a crate's own fmt::Write](/quest/m3/ts-fmt-calls.md) - `write!` with placeholders into a crate's own writer translates, its `write_str` seeing each call std makes - [Waiting: drop the lang fixture's mul_add allowance](/quest/m3/ts-fma-allowance.md) - the differential fails on any `mul_add` difference again once wasm32's `fma` rounds exactly diff --git a/quest/m3/ts-box-folds.md b/quest/m3/ts-box-folds.md deleted file mode 100644 index 9d2bd5994..000000000 --- a/quest/m3/ts-box-folds.md +++ /dev/null @@ -1,24 +0,0 @@ -# [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. diff --git a/ts/README.md b/ts/README.md index 7bc493958..ede6919a9 100644 --- a/ts/README.md +++ b/ts/README.md @@ -503,8 +503,11 @@ behind `&`, `&mut`, `Box`, `Arc`, or `Rc` is an `rt.Iter` of its items, `rt.iter of, std's or the crate's own: it reads that iterator by the methods std's vtable holds, such as `next`, `nth`, and `size_hint`, and folds it by `next`, as std's defaults read a trait object, so a `count` or `last` of a boxed `Chain` drops its items in the order the -trait object's does. A box drops the iterator it owns, and the last `Arc` the one they -share. `Arc::get_mut` and `Rc::get_mut` of a trait object lend its object while no other +trait object's does. A box of any iterator, a trait object or not, is `rt.iterBox` of it +wherever it is read, behind a `&mut` too: it forwards `next`, `nth`, `last`, and what else +std's `Iterator` for `Box` forwards, and reads the rest by `next`, `advance_by` and the +folds included, so a boxed `skip` of a zip skips through the zip's `nth` as std's does. A +box drops the iterator it owns, and the last `Arc` the one they share. `Arc::get_mut` and `Rc::get_mut` of a trait object lend its object while no other `Arc` or `Weak` shares it, but a `dyn Any`'s, whose value `Arc::downcast` gives back. A trait object of std's diff --git a/ts/fixtures/lang/dyns/expected/core/option.ts b/ts/fixtures/lang/dyns/expected/core/option.ts index 5a0b0d042..7f3f66121 100644 --- a/ts/fixtures/lang/dyns/expected/core/option.ts +++ b/ts/fixtures/lang/dyns/expected/core/option.ts @@ -61,6 +61,20 @@ export function map$0j05j69(self: rt.Arc | undefined, f: (a0: rt.Arc [rt.u8, rt.u8]): [rt.u8, rt.u8] | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function mapOr$1ttssgs(self: [rt.u8, rt.ByteSlice] | undefined, default_: [rt.u8, rt.ByteSlice], f: (a0: [rt.u8, rt.ByteSlice]) => [rt.u8, rt.ByteSlice]): [rt.u8, rt.ByteSlice] { + if (self === undefined) { + return default_; + } + return f(self); +} + export function mapOr$06rr3sb(self: rt.u8 | undefined, default_: rt.u8 | undefined, f: (a0: rt.u8) => rt.u8 | undefined): rt.u8 | undefined { if (self === undefined) { return default_; diff --git a/ts/fixtures/lang/dyns/expected/dyns.ts b/ts/fixtures/lang/dyns/expected/dyns.ts index a92e634d3..37ad64665 100644 --- a/ts/fixtures/lang/dyns/expected/dyns.ts +++ b/ts/fixtures/lang/dyns/expected/dyns.ts @@ -1,10 +1,10 @@ // Generated by rust2-ts. Do not edit. import * as rt from "./rt.ts"; -import { drop$Result_Rc_dyns_Noisy_Rc_dyn_Any, drop$Result_Rc_dyns_Square_Rc_dyn_Any, drop$Result_Rc_dyns_Tri_Rc_dyn_Any, of$Option_u8, of$dyns_Hits, of$dyns_Lease, of$dyns_Looped, of$dyns_Noisy, of$dyns_Square, of$dyns_Tri, of$ref_str, of$tuple2_u8_u8, of$u32, of$u8, of$unit, ofPlace$Option_u8, ofPlace$dyns_Tri, ofPlace$u32, ofPlace$u8, ofPlace$unit } from "./lib.ts"; +import { drop$Result_Rc_dyns_Noisy_Rc_dyn_Any, drop$Result_Rc_dyns_Square_Rc_dyn_Any, drop$Result_Rc_dyns_Tri_Rc_dyn_Any, drop$tuple2_dyns_Tagged_dyns_Tagged, of$Option_u8, of$dyns_Hits, of$dyns_Lease, of$dyns_Looped, of$dyns_Noisy, of$dyns_Square, of$dyns_Tri, of$ref_str, of$tuple2_u8_u8, of$u32, of$u8, of$unit, ofPlace$Option_u8, ofPlace$dyns_Tri, ofPlace$u32, ofPlace$u8, ofPlace$unit } from "./lib.ts"; import type * as Any from "./core/any.Any.ts"; import { thenSome$0d5am30 } from "./core/bool.ts"; -import { isSomeAnd$13v37g1, unwrapOr$1iemzn8 as option_unwrapOr$1iemzn8, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$1i542n2 as option_map$1i542n2, map$0oedb57 as option_map$0oedb57, map$08a6hpg as option_map$08a6hpg, map$1qfllpb as option_map$1qfllpb, map$0j05j69 as option_map$0j05j69, mapOr$06rr3sb as option_mapOr$06rr3sb, andThen$0v0bj8w as option_andThen$0v0bj8w, andThen$0ntiuws as option_andThen$0ntiuws } from "./core/option.ts"; +import { isSomeAnd$13v37g1, unwrapOr$1iemzn8 as option_unwrapOr$1iemzn8, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$1i542n2 as option_map$1i542n2, map$0oedb57 as option_map$0oedb57, map$08a6hpg as option_map$08a6hpg, map$1qfllpb as option_map$1qfllpb, map$0j05j69 as option_map$0j05j69, map$0z7s8q7 as option_map$0z7s8q7, mapOr$1ttssgs as option_mapOr$1ttssgs, mapOr$06rr3sb as option_mapOr$06rr3sb, andThen$0v0bj8w as option_andThen$0v0bj8w, andThen$0ntiuws as option_andThen$0ntiuws } from "./core/option.ts"; import { ok$00p9ap8, ok$1vbcgd7, ok$0lceojf, ok$1a014tb, map$1v8vvnp as result_map$1v8vvnp, map$1p3mw15 as result_map$1p3mw15, map$0zujxcv as result_map$0zujxcv } from "./core/result.ts"; import type * as Chunks from "./dyns.Chunks.ts"; import * as Countdown from "./dyns.Countdown.ts"; @@ -836,7 +836,7 @@ export function iters(data: rt.ByteSlice, out: rt.ByteVec): void { t2[Symbol.dispose](); return _05; })]; - const nth: rt.u8 | undefined = option_map$08a6hpg(rt.iterNth(boxed, 1, rt.drop), (t3: Tagged.Tagged): rt.u8 => { + const nth: rt.u8 | undefined = option_map$08a6hpg(rt.iterNth(rt.iterBox(boxed), 1, rt.drop), (t3: Tagged.Tagged): rt.u8 => { const _06: rt.u8 = t3._0; t3[Symbol.dispose](); return _06; @@ -846,7 +846,7 @@ export function iters(data: rt.ByteSlice, out: rt.ByteVec): void { put(out, rt.fmtFormat([args6[0], " ", args6[1], " "])); rt.drop(boxed); dropped(out); - const last: rt.u8 | undefined = option_map$08a6hpg(rt.ownedLast(rt.iterDyn(rt.iterChain(rt.iterSlice(tagged(front), rt.drop), rt.iterSlice(tagged(back), rt.drop))), rt.drop), (t4: Tagged.Tagged): rt.u8 => { + const last: rt.u8 | undefined = option_map$08a6hpg(rt.ownedLast(rt.iterBox(rt.iterDyn(rt.iterChain(rt.iterSlice(tagged(front), rt.drop), rt.iterSlice(tagged(back), rt.drop)))), rt.drop), (t4: Tagged.Tagged): rt.u8 => { const _07: rt.u8 = t4._0; t4[Symbol.dispose](); return _07; @@ -854,13 +854,13 @@ export function iters(data: rt.ByteSlice, out: rt.ByteVec): void { dropped(out); const args8: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(last, f, rt.u8Debug)]; put(out, rt.fmtFormat([args8[0], " "])); - const part2 = rt.ownedCount(rt.iterDyn(rt.iterChain(rt.iterSlice(tagged(back), rt.drop), rt.iterSlice(tagged(front), rt.drop))), rt.drop); + const part2 = rt.ownedCount(rt.iterBox(rt.iterDyn(rt.iterChain(rt.iterSlice(tagged(back), rt.drop), rt.iterSlice(tagged(front), rt.drop)))), rt.drop); const args10: rt.Fmt[] = [(f: rt.Formatter) => rt.usizeDisplay(part2, f)]; put(out, rt.fmtFormat([args10[0], " "])); dropped(out); const own: rt.Iter = rt.iterDyn(rt.iterFrom(new Countdown.Countdown(rt.u8Rem(b, 16)), (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop)); let sum: rt.u32 = 0; - const iter: rt.Iter = own; + const iter: rt.Iter = rt.iterBox(own); while (true) { const _166: rt.u8 | rt.Done = iter.next(); if (_166 === rt.DONE) { @@ -872,20 +872,20 @@ export function iters(data: rt.ByteSlice, out: rt.ByteVec): void { const args12: rt.Fmt[] = [(f: rt.Formatter) => rt.u32Display(sum, f)]; put(out, rt.fmtFormat([args12[0], " "])); dropped(out); - const nested: rt.Iter = rt.iterDyn(rt.iterFrom(new Countdown.Countdown(rt.u8Rem(a, 8)), (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop)); + const nested: rt.Iter = rt.iterDyn(rt.iterBox(rt.iterFrom(new Countdown.Countdown(rt.u8Rem(a, 8)), (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop))); const inner: Countdown.Countdown = new Countdown.Countdown(rt.u8Rem(b, 8)); - const first: rt.u8 | undefined = rt.iterToOption(rt.iterDyn(rt.iterFrom(inner, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it))).next()); + const first: rt.u8 | undefined = rt.iterToOption(rt.iterDyn(rt.iterBorrow(rt.iterBox(rt.iterFrom(inner, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it))))).next()); const second: rt.u8 | undefined = rt.iterToOption(Countdown.next$iter_Iterator(inner)); const erased: rt.Iter = rt.iterDyn(new rt.Range(rt.u8Rem(a, 4), rt.u8Rem(b, 8))); - const third: rt.u8 | undefined = rt.iterToOption(rt.iterDyn(rt.iterBorrow(erased)).next()); + const third: rt.u8 | undefined = rt.iterToOption(rt.iterDyn(rt.iterBorrow(rt.iterBox(rt.iterBorrow(erased)))).next()); const doubled: Countdown.Countdown = new Countdown.Countdown(rt.u8Rem(a, 8)); - const fourth: rt.u8 | undefined = rt.iterToOption(rt.iterDyn(rt.iterFrom(doubled, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it))).next()); - const mapped: rt.ByteVec = rt.iterToByteVec(rt.iterMap(rt.iterFrom(new Countdown.Countdown(rt.u8Rem(b, 8)), (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop), (x3: rt.u8): rt.u8 => { + const fourth: rt.u8 | undefined = rt.iterToOption(rt.iterDyn(rt.iterBorrow(rt.iterBox(rt.iterFrom(doubled, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it))))).next()); + const mapped: rt.ByteVec = rt.iterToByteVec(rt.iterMap(rt.iterBox(rt.iterFrom(new Countdown.Countdown(rt.u8Rem(b, 8)), (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop)), (x3: rt.u8): rt.u8 => { return x3 ^ 1; }), "next"); - const _233: rt.ByteVec = rt.iterToByteVec(nested, "next"); - const _235: rt.usize = rt.ownedCount(erased); - const _238: rt.usize = rt.ownedCount(rt.iterFrom(doubled, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop)); + const _233: rt.ByteVec = rt.iterToByteVec(rt.iterBox(nested), "next"); + const _235: rt.usize = rt.ownedCount(rt.iterBox(erased)); + const _238: rt.usize = rt.ownedCount(rt.iterBox(rt.iterFrom(doubled, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop))); const args14: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtList(rt.byteVecView(_233), f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(first, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(second, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(third, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(fourth, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtList(rt.byteVecView(mapped), f, rt.u8Debug), (f: rt.Formatter) => rt.usizeDisplay(_235, f), (f: rt.Formatter) => rt.usizeDisplay(_238, f)]; put(out, rt.fmtFormat([args14[0], " ", args14[1], " ", args14[2], " ", args14[3], " ", args14[4], " ", args14[5], " ", args14[6], " ", args14[7], " "])); dropped(out); @@ -894,15 +894,15 @@ export function iters(data: rt.ByteSlice, out: rt.ByteVec): void { const _262: [Countdown.Countdown, rt.Range] = [new Countdown.Countdown(rt.u8Rem(a, 8)), new rt.Range(rt.u8Rem(a, 4), rt.u8Rem(b, 8))]; const own2: Countdown.Countdown = _262[0]; const range: rt.Range = _262[1]; - const hints: [rt.usize, rt.usize | undefined][] = rt.arrayMap([rt.iterDyn(rt.iterFrom(own2, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it))), rt.iterDyn(rt.iterBorrow(range))], (it: rt.Iter): [rt.usize, rt.usize | undefined] => { + const hints: [rt.usize, rt.usize | undefined][] = rt.arrayMap([rt.iterDyn(rt.iterBorrow(rt.iterBox(rt.iterFrom(own2, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it))))), rt.iterDyn(rt.iterBorrow(rt.iterBox(rt.iterBorrow(range))))], (it: rt.Iter): [rt.usize, rt.usize | undefined] => { return it.sizeHint(); }); let held: Countdown.Countdown = new Countdown.Countdown(rt.u8Rem(b, 8)); let lent2: rt.Place = rt.place(() => held, (value4) => held = value4); const layered: rt.Place> = rt.place(() => lent2, (value5) => lent2 = value5); - const fifth: rt.u8 | undefined = rt.iterToOption(rt.iterDyn(rt.iterFrom(layered.v.v, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it))).next()); + const fifth: rt.u8 | undefined = rt.iterToOption(rt.iterDyn(rt.iterBorrow(rt.iterBox(rt.iterFrom(layered.v.v, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it))))).next()); const sixth: rt.u8 | undefined = rt.iterToOption(Countdown.next$iter_Iterator(layered.v.v)); - const _301: rt.usize = rt.ownedCount(rt.iterFrom(held, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop)); + const _301: rt.usize = rt.ownedCount(rt.iterBox(rt.iterFrom(held, (it: Countdown.Countdown) => Countdown.next$iter_Iterator(it), rt.drop))); const args16: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtList(hints, f, (value: [rt.usize, rt.usize | undefined], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.usizeDebug(value[0], f), (f: rt.Formatter) => rt.fmtOption(value[1], f, rt.usizeDebug)], f)), (f: rt.Formatter) => rt.fmtOption(fifth, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(sixth, f, rt.u8Debug), (f: rt.Formatter) => rt.usizeDisplay(_301, f)]; put(out, rt.fmtFormat([args16[0], " ", args16[1], " ", args16[2], " ", args16[3], " "])); dropped(out); @@ -917,18 +917,18 @@ export function iters(data: rt.ByteSlice, out: rt.ByteVec): void { return x4; }), new rt.Range(0, rt.u8Rem(b, 4)), "len"); }; - const owned: [rt.u8, rt.u8][] = rt.iterToArray(zipped(), "next", 2); - const lent3: [rt.u8, rt.u8][] = rt.iterToArray(rt.iterBorrow(zipped()), "next", 2); + const owned: [rt.u8, rt.u8][] = rt.iterToArray(rt.iterBox(zipped()), "next", 2); + const lent3: [rt.u8, rt.u8][] = rt.iterToArray(rt.iterBorrow(rt.iterBox(rt.iterBorrow(zipped()))), "next", 2); const _339: rt.RefCell = rt.refCellBorrow(seen2); const args18: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtList(owned, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.fmtList(lent3, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.fmtList(rt.byteVecView(_339.value), f, rt.u8Debug)]; const _335: string = rt.fmtFormat([args18[0], " ", args18[1], " ", args18[2], " "]); rt.refRelease(_339); put(out, _335); const split: Chunks.Chunks = new of$dyns_Lease({ _0: rt.byteSliceToByteVec(rt.byteSliceRange(data, 2)), _1: rt.usizeAdd(rt.u8Rem(b, 4) as rt.usize, 1) }); - const lens_: rt.usize[] = rt.iterToArray(rt.iterMap(split.chunks$Chunks(), (a0: rt.ByteSlice): rt.usize => { + const lens_: rt.usize[] = rt.iterToArray(rt.iterMap(rt.iterBox(split.chunks$Chunks()), (a0: rt.ByteSlice): rt.usize => { return a0.length; }), "next", 4); - const _369: rt.usize = rt.ownedCount(split.chunks$Chunks()); + const _369: rt.usize = rt.ownedCount(rt.iterBox(split.chunks$Chunks())); const args20: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtList(lens_, f, rt.usizeDebug), (f: rt.Formatter) => rt.usizeDisplay(_369, f)]; put(out, rt.fmtFormat([args20[0], " ", args20[1], " "])); const part3 = drain(rt.iterDyn(rt.iterBorrow(rt.iterFuse(rt.iterFrom({ _0: rt.u8Rem(a, 4) }, (it: Resuming.Resuming) => Resuming.next$iter_Iterator(it)))))); @@ -1311,4 +1311,228 @@ export function pointers(dataData: Uint8Array, dataStart: number, dataLen: numbe } } +/** A tag of `t`, below 0x80, which logs it with the high bit set as it is made. */ +export function made(t: rt.u8): Tagged.Tagged { + rt.localKeyWithBorrowMut(DROPS, (d: rt.ByteVec): undefined => { + rt.byteVecPush(d, t | 128); + }); + return new Tagged.Tagged(t); +} + +/** + * A skip of a zip std reads by index, of items that log as they are made and dropped, the + * left side's below 0x40 and the right's above: its `next` skips through the zip's `nth`, + * which makes and drops each skipped pair a side at a time, where its folds make the pair + * whole. + */ +export function skipped(data: rt.ByteSlice): rt.Iter<[Tagged.Tagged, Tagged.Tagged]> { + const _4: [rt.u8, rt.ByteSlice] = option_mapOr$1ttssgs((data.length !== 0 ? [data.data[data.start], new rt.ByteSlice(data.data, data.start + 1, data.length - 1)] as [rt.u8, rt.ByteSlice] : undefined) as [rt.u8, rt.ByteSlice] | undefined, [0, data] as [rt.u8, rt.ByteSlice], (_2: [rt.u8, rt.ByteSlice]): [rt.u8, rt.ByteSlice] => { + return [_2[0], _2[1]] as [rt.u8, rt.ByteSlice]; + }); + const n: rt.u8 = _4[0]; + const _10: rt.usize = rt.usizeRem(n as rt.usize, rt.usizeAdd(_4[1].length, 1)); + const slice: rt.ByteSlice = _4[1]; + if (_10 > slice.length) { + rt.panic("mid > len"); + } + return rt.iterSkip(rt.iterZip(rt.iterMap(rt.iterSlice(rt.byteSliceView(new rt.ByteSlice(slice.data, slice.start, _10))), (_24: rt.u8): Tagged.Tagged => { + return made(_24 & 63); + }), rt.iterMap(rt.iterSlice(rt.byteSliceView(new rt.ByteSlice(slice.data, slice.start + _10, slice.length - _10))), (_25: rt.u8): Tagged.Tagged => { + return made((_25 & 63) | 64); + }), [true, true], rt.drop, rt.drop), rt.u8Rem(n, 3) as rt.usize, drop$tuple2_dyns_Tagged_dyns_Tagged); +} + +export function tags(pair: [Tagged.Tagged, Tagged.Tagged] | undefined): [rt.u8, rt.u8] | undefined { + return option_map$0z7s8q7(pair, (p: [Tagged.Tagged, Tagged.Tagged]): [rt.u8, rt.u8] => { + const _02: [rt.u8, rt.u8] = [p[0]._0, p[1]._0]; + drop$tuple2_dyns_Tagged_dyns_Tagged(p); + return _02; + }); +} + +/** + * A box of an iterator, owned, behind a `&mut`, of a `&mut`, of a box, and as a trait + * object: std's `Iterator` for `Box` forwards `next`, `size_hint`, `nth`, `last`, and + * the double-ended and exact-size methods to `I`, and reads by `next` for the rest, its + * `advance_by` and folds included. + */ +export function boxes(data: rt.ByteSlice, out: rt.ByteVec): void { + const it: () => rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = (): rt.Iter<[Tagged.Tagged, Tagged.Tagged]> => { + return skipped(data); + }; + const boxed: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = it(); + const hint: [[rt.usize, rt.usize | undefined], rt.usize] = [rt.iterBox(boxed).sizeHint(), rt.iterBox(boxed).len()]; + const ends: [[rt.u8, rt.u8] | undefined, [rt.u8, rt.u8] | undefined] = [tags(rt.iterToOption(boxed.next())), tags(rt.iterToOption(boxed.nextBack()))]; + const nths: [[rt.u8, rt.u8] | undefined, [rt.u8, rt.u8] | undefined] = [tags(rt.iterNth(rt.iterBox(boxed), 1, drop$tuple2_dyns_Tagged_dyns_Tagged)), tags(rt.iterNthBack(rt.iterBox(boxed), 0, drop$tuple2_dyns_Tagged_dyns_Tagged))]; + dropped(out); + const args2: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.usizeDebug(hint[0][0], f), (f: rt.Formatter) => rt.fmtOption(hint[0][1], f, rt.usizeDebug)], f), (f: rt.Formatter) => rt.usizeDebug(hint[1], f)], f), (f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.fmtOption(ends[0], f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.fmtOption(ends[1], f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))], f), (f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.fmtOption(nths[0], f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.fmtOption(nths[1], f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))], f)]; + put(out, rt.fmtFormat([args2[0], " ", args2[1], " ", args2[2], " "])); + dropped(out); + const part = tags(rt.ownedLast(rt.iterBox(it()), drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args4: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + put(out, rt.fmtFormat([args4[0], " "])); + dropped(out); + const part2 = tags(rt.ownedLast(rt.iterBox(it()), drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args6: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part2, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + put(out, rt.fmtFormat([args6[0], " "])); + dropped(out); + const part3 = rt.ownedCount(rt.iterBox(it()), drop$tuple2_dyns_Tagged_dyns_Tagged); + const args8: rt.Fmt[] = [(f: rt.Formatter) => rt.usizeDisplay(part3, f)]; + put(out, rt.fmtFormat([args8[0], " "])); + dropped(out); + const sum: rt.u32 = rt.iterFold(rt.iterBox(it()), 0, (n2: rt.u32, _3: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { + const x: Tagged.Tagged = _3[0]; + const y: Tagged.Tagged = _3[1]; + const _02: rt.u32 = rt.u32WrappingAdd(rt.u32WrappingMul(n2, 7), (x._0 ^ y._0) as rt.u32); + y[Symbol.dispose](); + x[Symbol.dispose](); + return _02; + }); + dropped(out); + const args10: rt.Fmt[] = [(f: rt.Formatter) => rt.u32Display(sum, f)]; + put(out, rt.fmtFormat([args10[0], " "])); + rt.iterForEach(rt.iterBox(it()), (_24: [Tagged.Tagged, Tagged.Tagged]): undefined => { + const x2: Tagged.Tagged = _24[0]; + const y2: Tagged.Tagged = _24[1]; + const arg = x2._0; + const _142: rt.Fmt = (f: rt.Formatter) => rt.u8Display(arg, f); + const arg2 = y2._0; + const args42: rt.Fmt[] = [_142, (f: rt.Formatter) => rt.u8Display(arg2, f)]; + put(out, rt.fmtFormat([args42[0], " ", args42[1], " "])); + y2[Symbol.dispose](); + x2[Symbol.dispose](); + }); + dropped(out); + const found: rt.usize | undefined = rt.iterPosition(rt.iterBox(it()), (_25: [Tagged.Tagged, Tagged.Tagged]): boolean => { + const x3: Tagged.Tagged = _25[0]; + const _03: boolean = rt.u8Rem(x3._0, 2) === 1; + x3[Symbol.dispose](); + _25[1][Symbol.dispose](); + return _03; + }); + dropped(out); + const args12: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(found, f, rt.usizeDebug)]; + put(out, rt.fmtFormat([args12[0], " "])); + const found2: [rt.u8, rt.u8] | undefined = tags(rt.iterFind(rt.iterBox(it()), (_26: [Tagged.Tagged, Tagged.Tagged]): boolean => { + return rt.u8Rem(_26[1]._0, 3) === 0; + }, drop$tuple2_dyns_Tagged_dyns_Tagged)); + dropped(out); + const _148: boolean = rt.iterAny(rt.iterBox(it()), (_28: [Tagged.Tagged, Tagged.Tagged]): boolean => { + const x4: Tagged.Tagged = _28[0]; + const _05: boolean = x4._0 > 8; + x4[Symbol.dispose](); + _28[1][Symbol.dispose](); + return _05; + }); + const args14: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(found2, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.fmtBool(_148, f)]; + put(out, rt.fmtFormat([args14[0], " ", args14[1], " "])); + dropped(out); + const part4 = tags(rt.iterMaxByKey(rt.iterBox(it()), (p: [Tagged.Tagged, Tagged.Tagged]): rt.u8 => { + return p[1]._0; + }, rt.lt, undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args16: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part4, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + put(out, rt.fmtFormat([args16[0], " "])); + dropped(out); + const all: [rt.u8, rt.u8][] = rt.iterToArray(rt.iterMap(rt.iterSlice(rt.iterToArray(rt.iterBox(it()), "next", 2), drop$tuple2_dyns_Tagged_dyns_Tagged), (p2: [Tagged.Tagged, Tagged.Tagged]): [rt.u8, rt.u8] => { + const _07: [rt.u8, rt.u8] = [p2[0]._0, p2[1]._0]; + drop$tuple2_dyns_Tagged_dyns_Tagged(p2); + return _07; + }), "next", 2, true, 2); + dropped(out); + const args18: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtList(all, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + put(out, rt.fmtFormat([args18[0], " "])); + const back: rt.u32 = rt.iterFold(rt.iterRev(rt.iterBox(it())), 0, (n3: rt.u32, _33: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { + const x5: Tagged.Tagged = _33[0]; + const y3: Tagged.Tagged = _33[1]; + const _08: rt.u32 = rt.u32WrappingAdd(rt.u32WrappingMul(n3, 5), (x5._0 ^ y3._0) as rt.u32); + y3[Symbol.dispose](); + x5[Symbol.dispose](); + return _08; + }); + dropped(out); + const _208: rt.u32 = rt.iterSum(rt.iterMap(rt.iterBox(it()), (_211: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { + const x6: Tagged.Tagged = _211[0]; + const y4: Tagged.Tagged = _211[1]; + const _09: rt.u32 = rt.u32Add(x6._0 as rt.u32, y4._0 as rt.u32); + y4[Symbol.dispose](); + x6[Symbol.dispose](); + return _09; + }), rt.u32Add, 0); + const args20: rt.Fmt[] = [(f: rt.Formatter) => rt.u32Display(back, f), (f: rt.Formatter) => rt.u32Display(_208, f)]; + put(out, rt.fmtFormat([args20[0], " ", args20[1], " "])); + dropped(out); + const _227: rt.usize = rt.ownedCount(rt.iterSkip(rt.iterBox(it()), 1, drop$tuple2_dyns_Tagged_dyns_Tagged), drop$tuple2_dyns_Tagged_dyns_Tagged); + const _232: rt.usize = rt.ownedCount(rt.iterStepBy(rt.iterBox(it()), 2, drop$tuple2_dyns_Tagged_dyns_Tagged), drop$tuple2_dyns_Tagged_dyns_Tagged); + const args22: rt.Fmt[] = [(f: rt.Formatter) => rt.usizeDisplay(_227, f), (f: rt.Formatter) => rt.usizeDisplay(_232, f)]; + put(out, rt.fmtFormat([args22[0], " ", args22[1], " "])); + dropped(out); + const _253: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = rt.iterChain(rt.iterBox(it()), rt.iterOption(undefined as [Tagged.Tagged, Tagged.Tagged] | undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const part5 = tags(rt.iterNth(_253, 1, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args24: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part5, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + const _246: string = rt.fmtFormat([args24[0], " "]); + rt.drop(_253); + put(out, _246); + dropped(out); + const last: [rt.u8, rt.u8] | undefined = tags(rt.ownedLast(rt.iterBorrow(rt.iterBox(rt.iterBorrow(it()))), drop$tuple2_dyns_Tagged_dyns_Tagged)); + dropped(out); + const args26: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(last, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + put(out, rt.fmtFormat([args26[0], " "])); + const boxed3: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = it(); + const _285: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = rt.iterChain(rt.iterBorrow(rt.iterBox(rt.iterBorrow(boxed3))), rt.iterOption(undefined as [Tagged.Tagged, Tagged.Tagged] | undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const nth: [rt.u8, rt.u8] | undefined = tags(rt.iterNth(_285, 1, drop$tuple2_dyns_Tagged_dyns_Tagged)); + rt.drop(_285); + dropped(out); + const n: rt.usize = rt.ownedCount(rt.iterBorrow(rt.iterBox(rt.iterBorrow(boxed3))), drop$tuple2_dyns_Tagged_dyns_Tagged); + dropped(out); + const args28: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(nth, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.usizeDisplay(n, f)]; + put(out, rt.fmtFormat([args28[0], " ", args28[1], " "])); + const boxed4: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = it(); + const first: [rt.u8, rt.u8] | undefined = tags(rt.iterToOption(boxed4.next())); + const sum2: rt.u32 = rt.iterFold(rt.iterBorrow(rt.iterBox(rt.iterBorrow(boxed4))), 0, (n4: rt.u32, _34: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { + const x7: Tagged.Tagged = _34[0]; + const y5: Tagged.Tagged = _34[1]; + const _010: rt.u32 = rt.u32WrappingAdd(n4, (x7._0 ^ y5._0) as rt.u32); + y5[Symbol.dispose](); + x7[Symbol.dispose](); + return _010; + }); + dropped(out); + const args30: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(first, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.u32Display(sum2, f)]; + put(out, rt.fmtFormat([args30[0], " ", args30[1], " "])); + dropped(out); + const part6 = tags(rt.ownedLast(rt.iterBox(rt.iterBorrow(skipped(data))), drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args32: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part6, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + put(out, rt.fmtFormat([args32[0], " "])); + dropped(out); + const part7 = rt.ownedCount(rt.iterBox(rt.iterBorrow(skipped(data))), drop$tuple2_dyns_Tagged_dyns_Tagged); + const args34: rt.Fmt[] = [(f: rt.Formatter) => rt.usizeDisplay(part7, f)]; + put(out, rt.fmtFormat([args34[0], " "])); + dropped(out); + const erased: () => rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = (): rt.Iter<[Tagged.Tagged, Tagged.Tagged]> => { + return rt.iterDyn(skipped(data)); + }; + const _378: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = rt.iterChain(rt.iterBox(erased()), rt.iterOption(undefined as [Tagged.Tagged, Tagged.Tagged] | undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const part8 = tags(rt.iterNth(_378, 1, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args36: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part8, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + const _371: string = rt.fmtFormat([args36[0], " "]); + rt.drop(_378); + put(out, _371); + dropped(out); + const _395: [rt.u8, rt.u8] | undefined = tags(rt.ownedLast(rt.iterBox(erased()), drop$tuple2_dyns_Tagged_dyns_Tagged)); + const _400: rt.usize = rt.ownedCount(rt.iterBox(erased()), drop$tuple2_dyns_Tagged_dyns_Tagged); + const args38: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(_395, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.usizeDisplay(_400, f)]; + put(out, rt.fmtFormat([args38[0], " ", args38[1], " "])); + dropped(out); + const boxed5: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = erased(); + const _423: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = rt.iterChain(rt.iterBorrow(boxed5), rt.iterOption(undefined as [Tagged.Tagged, Tagged.Tagged] | undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const part9 = tags(rt.iterNth(_423, 1, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args40: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part9, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + const _416: string = rt.fmtFormat([args40[0], " "]); + rt.drop(_423); + put(out, _416); + dropped(out); + rt.drop(boxed5); + dropped(out); +} + //# sourceMappingURL=dyns.ts.map diff --git a/ts/fixtures/lang/dyns/expected/lib.ts b/ts/fixtures/lang/dyns/expected/lib.ts index 77ef711e7..62b3f8161 100644 --- a/ts/fixtures/lang/dyns/expected/lib.ts +++ b/ts/fixtures/lang/dyns/expected/lib.ts @@ -2,12 +2,13 @@ import * as rt from "./rt.ts"; import type * as Any from "./core/any.Any.ts"; -import { sides$dyns_Shape_u32, intoArea$dyns_Shape_u32, larger$dyns_Shape_u32, tally$dyns_Shape_u32, area$dyns_Shape_u32, grow$dyns_Shape_u32, dyns, shared, asAny$dyns_Erased_u32, asAnyMut$dyns_Erased_u32, key$dyns_Keyed_u32, anys, fns, iters, pointers } from "./dyns.ts"; +import { sides$dyns_Shape_u32, intoArea$dyns_Shape_u32, larger$dyns_Shape_u32, tally$dyns_Shape_u32, area$dyns_Shape_u32, grow$dyns_Shape_u32, dyns, shared, asAny$dyns_Erased_u32, asAnyMut$dyns_Erased_u32, key$dyns_Keyed_u32, anys, fns, iters, pointers, boxes } from "./dyns.ts"; import * as Hits from "./dyns.Hits.ts"; import * as Lease from "./dyns.Lease.ts"; import * as Looped from "./dyns.Looped.ts"; import * as Noisy from "./dyns.Noisy.ts"; import * as Square from "./dyns.Square.ts"; +import type * as Tagged from "./dyns.Tagged.ts"; import * as Tri from "./dyns.Tri.ts"; export function drop$Result_Rc_dyns_Noisy_Rc_dyn_Any(_1: rt.Result, rt.Arc>): void { @@ -60,6 +61,11 @@ export function drop$Result_u16_boxed_Box_dyn_Any(_1: rt.Result } } +export function drop$tuple2_dyns_Tagged_dyns_Tagged(_1: [Tagged.Tagged, Tagged.Tagged]): void { + _1[0][Symbol.dispose](); + _1[1][Symbol.dispose](); +} + export class of$Option_u8 { v: rt.u8 | undefined; @@ -465,18 +471,20 @@ export class ofPlace$unit { * their count, so a case added at the end moves no other. */ export function cases(): [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined][] { - return [["dyns::dyns", (_22: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): undefined => { + return [["dyns::dyns", (_24: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): undefined => { dyns(data.data, data.start, data.length, out); - }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::shared", (_23: rt.u8, data2: rt.ByteSlice, out2: rt.ByteVec): undefined => { + }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::shared", (_25: rt.u8, data2: rt.ByteSlice, out2: rt.ByteVec): undefined => { shared(data2.data, data2.start, data2.length, out2); - }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::anys", (_24: rt.u8, data3: rt.ByteSlice, out3: rt.ByteVec): undefined => { + }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::anys", (_26: rt.u8, data3: rt.ByteSlice, out3: rt.ByteVec): undefined => { anys(data3.data, data3.start, data3.length, out3); - }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::fns", (_25: rt.u8, data4: rt.ByteSlice, out4: rt.ByteVec): undefined => { + }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::fns", (_27: rt.u8, data4: rt.ByteSlice, out4: rt.ByteVec): undefined => { fns(data4, out4); - }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::pointers", (_26: rt.u8, data5: rt.ByteSlice, out5: rt.ByteVec): undefined => { + }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::pointers", (_28: rt.u8, data5: rt.ByteSlice, out5: rt.ByteVec): undefined => { pointers(data5.data, data5.start, data5.length, out5); - }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::iters", (_27: rt.u8, data6: rt.ByteSlice, out6: rt.ByteVec): undefined => { + }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::iters", (_29: rt.u8, data6: rt.ByteSlice, out6: rt.ByteVec): undefined => { iters(data6, out6); + }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::boxes", (_210: rt.u8, data7: rt.ByteSlice, out7: rt.ByteVec): undefined => { + boxes(data7, out7); }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]]; } diff --git a/ts/fixtures/lang/dyns/src/dyns.rs b/ts/fixtures/lang/dyns/src/dyns.rs index 10cf72140..cf6969e35 100644 --- a/ts/fixtures/lang/dyns/src/dyns.rs +++ b/ts/fixtures/lang/dyns/src/dyns.rs @@ -9,6 +9,7 @@ //! `dyn Iterator`, `dyn DoubleEndedIterator`, `dyn ExactSizeIterator`, or //! `dyn FusedIterator` of std's iterators or the crate's own, borrowed, boxed, or shared, //! reads by its vtable's methods and folds by `next`, dropping what it owns in std's order. +//! A box of an iterator reads by what std's box forwards and folds by `next` too. use std::any::Any; use std::cell::RefCell; @@ -1062,3 +1063,125 @@ pub fn pointers(data: &[u8], out: &mut Vec) { let g: Arc u8> = Arc::from(boxed); put(out, &format!("{} {}", f(*b), g(*a))); } + +/// A tag of `t`, below 0x80, which logs it with the high bit set as it is made. +fn made(t: u8) -> Tagged { + DROPS.with_borrow_mut(|d| d.push(t | 0x80)); + Tagged(t) +} + +/// A skip of a zip std reads by index, of items that log as they are made and dropped, the +/// left side's below 0x40 and the right's above: its `next` skips through the zip's `nth`, +/// which makes and drops each skipped pair a side at a time, where its folds make the pair +/// whole. +fn skipped(data: &[u8]) -> impl DoubleEndedIterator + ExactSizeIterator + '_ { + let (n, rest) = data.split_first().map_or((0, data), |(n, rest)| (*n, rest)); + let (left, right) = rest.split_at(usize::from(n) % (rest.len() + 1)); + let left = left.iter().map(|&t| made(t & 0x3f)); + left.zip(right.iter().map(|&t| made(t & 0x3f | 0x40))) + .skip(usize::from(n % 3)) +} + +fn tags(pair: Option<(Tagged, Tagged)>) -> Option<(u8, u8)> { + pair.map(|p| (p.0.0, p.1.0)) +} + +/// A box of an iterator, owned, behind a `&mut`, of a `&mut`, of a box, and as a trait +/// object: std's `Iterator` for `Box` forwards `next`, `size_hint`, `nth`, `last`, and +/// the double-ended and exact-size methods to `I`, and reads by `next` for the rest, its +/// `advance_by` and folds included. +pub fn boxes(data: &[u8], out: &mut Vec) { + let it = || Box::new(skipped(data)); + + // What it forwards. + let mut boxed = it(); + let hint = (boxed.size_hint(), boxed.len()); + let ends = (tags(boxed.next()), tags(boxed.next_back())); + let nths = (tags(boxed.nth(1)), tags(boxed.nth_back(0))); + dropped(out); + put(out, &format!("{hint:?} {ends:?} {nths:?} ")); + drop(boxed); + dropped(out); + put(out, &format!("{:?} ", tags(it().last()))); + dropped(out); + put(out, &format!("{:?} ", tags(Box::new(it()).last()))); + dropped(out); + + // What it reads by `next`. + put(out, &format!("{} ", it().count())); + dropped(out); + let sum = it().fold(0u32, |n, (x, y)| n.wrapping_mul(7).wrapping_add(u32::from(x.0 ^ y.0))); + dropped(out); + put(out, &format!("{sum} ")); + it().for_each(|(x, y)| put(out, &format!("{} {} ", x.0, y.0))); + dropped(out); + let found = it().position(|(x, _)| x.0 % 2 == 1); + dropped(out); + put(out, &format!("{found:?} ")); + let found = tags(it().find(|(_, y)| y.0 % 3 == 0)); + dropped(out); + put(out, &format!("{found:?} {} ", it().any(|(x, _)| x.0 > 8))); + dropped(out); + put(out, &format!("{:?} ", tags(it().max_by_key(|p| p.1.0)))); + dropped(out); + let all: Vec<(u8, u8)> = it().collect::>().into_iter().map(|p| (p.0.0, p.1.0)).collect(); + dropped(out); + put(out, &format!("{all:?} ")); + let back = it() + .rev() + .fold(0u32, |n, (x, y)| n.wrapping_mul(5).wrapping_add(u32::from(x.0 ^ y.0))); + dropped(out); + put( + out, + &format!( + "{back} {} ", + it().map(|(x, y)| u32::from(x.0) + u32::from(y.0)).sum::() + ), + ); + dropped(out); + put(out, &format!("{} {} ", it().skip(1).count(), it().step_by(2).count())); + dropped(out); + // `Chain::nth` advances its first half by `advance_by`, which the box reads by `next`. + put(out, &format!("{:?} ", tags(it().chain(None).nth(1)))); + dropped(out); + + // Behind a `&mut`, which forwards to the box, and so reads by `next` too, `last` included. + let mut boxed = it(); + let last = tags((&mut boxed).last()); + dropped(out); + put(out, &format!("{last:?} ")); + let mut boxed = it(); + let nth = tags((&mut boxed).chain(None).nth(1)); + dropped(out); + let n = (&mut boxed).count(); + dropped(out); + put(out, &format!("{nth:?} {n} ")); + let mut boxed = it(); + let first = tags(boxed.next()); + let sum = (&mut boxed).fold(0u32, |n, (x, y)| n.wrapping_add(u32::from(x.0 ^ y.0))); + dropped(out); + put(out, &format!("{first:?} {sum} ")); + drop(boxed); + dropped(out); + + // A box of a `&mut`, whose `last` is the borrow's, which folds what it borrows. + let mut held = skipped(data); + put(out, &format!("{:?} ", tags(Box::new(&mut held).last()))); + dropped(out); + let mut held = skipped(data); + put(out, &format!("{} ", Box::new(&mut held).count())); + dropped(out); + + // A box of a trait object, which reads by `next` where the object reads by its vtable. + let erased = || -> Box + '_> { Box::new(skipped(data)) }; + put(out, &format!("{:?} ", tags(erased().chain(None).nth(1)))); + dropped(out); + put(out, &format!("{:?} {} ", tags(erased().last()), erased().count())); + dropped(out); + let mut boxed = erased(); + let lent: &mut dyn Iterator = &mut *boxed; + put(out, &format!("{:?} ", tags(lent.chain(None).nth(1)))); + dropped(out); + drop(boxed); + dropped(out); +} diff --git a/ts/fixtures/lang/dyns/src/lib.rs b/ts/fixtures/lang/dyns/src/lib.rs index 77c77e7f1..19017113e 100644 --- a/ts/fixtures/lang/dyns/src/lib.rs +++ b/ts/fixtures/lang/dyns/src/lib.rs @@ -22,5 +22,6 @@ fn cases() -> Vec<(&'static str, Case)> { ("dyns::fns", |_, data, out| dyns::fns(data, out)), ("dyns::pointers", |_, data, out| dyns::pointers(data, out)), ("dyns::iters", |_, data, out| dyns::iters(data, out)), + ("dyns::boxes", |_, data, out| dyns::boxes(data, out)), ] } diff --git a/ts/runtime/rt/iter.ts b/ts/runtime/rt/iter.ts index e884e48f8..85db6a5fb 100644 --- a/ts/runtime/rt/iter.ts +++ b/ts/runtime/rt/iter.ts @@ -589,6 +589,15 @@ export function iterDyn(it: Iter): Iter { return new Dyn(it); } +/** + * A `Box` of `it`: what std's `Iterator` for `Box` forwards, `last` among them, as `it` + * does it, and the rest by `next`, `advance_by` and the folds included. It drops `it` as it + * drops. + */ +export function iterBox(it: Iter): Iter { + return new Boxed(it); +} + // How std's `Vec` and `VecDeque` reserve for an iterator they collect or extend by, of // elements `size` bytes each, which panics past what they may hold: a `TrustedLen` one's // upper bound first, and else, after each item that finds them full, the lower bound and @@ -1493,6 +1502,8 @@ function count(it: Iter, drop: Drop | undefined): number { * does. By `fold`, each item drops as the next replaces it. */ function last(it: Iter, drop: Drop | undefined): T | Done { + // std's of a box: what it holds, by its own. + if (it instanceof Boxed) return last(it.inner, drop); if ((it instanceof SliceIter && drop !== undefined) || (it instanceof BTreeIter && it.back)) { // std's, of a `Vec`'s or an array's, and of a B-tree's `into_keys` and // `into_values`: the last item, and then the rest drop with it. @@ -2059,8 +2070,11 @@ class SuccessorsIter extends Iter implements Disposable { } } -/** What std's vtable of an iterator holds, as `inner` does it, which it drops with itself. */ -class Dyn extends Iter implements Disposable { +/** + * An iterator of `inner` that forwards what std's `Iterator` for `Box` and a trait + * object's vtable both have, and drops it as it drops. + */ +abstract class Forward extends Iter implements Disposable { readonly inner: Iter; constructor(inner: Iter) { @@ -2084,14 +2098,6 @@ class Dyn extends Iter implements Disposable { return this.inner.len(); } - override advanceBy(n: number, drop?: Drop): number { - return this.inner.advanceBy(n, drop); - } - - override advanceBackBy(n: number, drop?: Drop): number { - return this.inner.advanceBackBy(n, drop); - } - override nth(n: number, drop?: Drop): T | Done { return this.inner.nth(n, drop); } @@ -2105,6 +2111,20 @@ class Dyn extends Iter implements Disposable { } } +/** A box, whose `last` is `inner`'s too, which `last` dispatches on. */ +class Boxed extends Forward {} + +/** What std's vtable of an iterator holds, as `inner` does it: a box's, and `advance_by` too. */ +class Dyn extends Forward { + override advanceBy(n: number, drop?: Drop): number { + return this.inner.advanceBy(n, drop); + } + + override advanceBackBy(n: number, drop?: Drop): number { + return this.inner.advanceBackBy(n, drop); + } +} + /** * An iterator borrowed by `&mut`, which forwards only what std's `impl Iterator for &mut * I` does, its folds included, as std's specializes them for a sized `I`, and which diff --git a/ts/src/lower/iter.rs b/ts/src/lower/iter.rs index ba0d105b2..d57ef63ec 100644 --- a/ts/src/lower/iter.rs +++ b/ts/src/lower/iter.rs @@ -208,8 +208,44 @@ impl<'tcx> Body<'_, '_, 'tcx> { /// type without a mapping. One that owns what it yields, by value, is given what drops /// each, and the crate's own iterator what drops it. pub fn into_iter<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, value: Expr, span: Span) -> Option { + let (peeled, value) = peel_iter(b, ty, value); + let it = peeled_into_iter(b, peeled, value, span)?; + Some(boxes(b, ty, it)) +} + +/// `it`, the `rt.Iter` of what `peel_iter` read a `ty` through, read through `ty`'s boxes +/// as std's `Iterator` for `Box` reads one: by what it forwards, and else by `next`. +/// Boxes before the first reference are one `rt.iterBox`, and a box past it makes that +/// reference fold by `next` too, whatever the box holds. +fn boxes<'tcx>(b: &Body<'_, '_, 'tcx>, mut ty: Ty<'tcx>, it: Expr) -> Expr { + let held = |ty: Ty<'tcx>| ty.boxed_ty().filter(|held| b.t.iter_item(*held).is_some()); + let outer = held(ty).is_some(); + while let Some(inner) = held(ty) { + ty = inner; + } + let mut end = ty; + let borrowed = loop { + if held(end).is_some() { + break true; + } + match *end.kind() { + ty::Ref(_, inner, _) => end = inner, + _ => break false, + } + }; + let it = match borrowed { + true => Expr::rt("iterBorrow", vec![Expr::rt("iterBox", vec![it])]), + false => it, + }; + match outer { + true => Expr::rt("iterBox", vec![it]), + false => it, + } +} + +/// `into_iter` of `value`, a `ty` `peel_iter` read through. +fn peeled_into_iter<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, value: Expr, span: Span) -> Option { let tcx = b.t.tcx; - let (ty, value) = peel_iter(b, ty, value); let (ty, value) = match unbox_ref(tcx, ty) { unboxed if unboxed != ty => (unboxed, b.t.pointee_value(ty, value)), _ => (ty, value), @@ -595,7 +631,8 @@ pub fn call<'tcx>( let mut values = args.into_iter(); // What it reads through boxes and references, while std picks each specialization by // `self_ty`, which a box implements none of. - let (iter_ty, recv) = peel_iter(b, self_ty, values.next()?); + let value = values.next()?; + let (iter_ty, recv) = peel_iter(b, self_ty, value.clone()); let rest: Vec = values.collect(); // What a consumer returns for `None`, after its other arguments, where that is `rt.None`. let none = b.t.none_arg(item); @@ -609,14 +646,14 @@ pub fn call<'tcx>( None => recv.member("nextBack").call(Vec::new()), }, _ => { - let recv = into_iter(b, iter_ty, recv, span)?; + let recv = into_iter(b, self_ty, value, span)?; let droppers = [b.t.dropper(item, span)].into_iter().chain(none).collect(); return Some(Expr::rt("iterNthBack", tail([vec![recv], rest].concat(), droppers))); } }; return Some(Expr::rt("iterToOption", [item].into_iter().chain(none).collect())); } - let recv = into_iter(b, iter_ty, recv, span)?; + let recv = into_iter(b, self_ty, value, span)?; // `rt.iter(recv, ...args)`, or `peekable` of a `Peekable`'s own. let method = |name: &str, args: Vec| { let of = match owner { From b6752bcc5ede61af41afdcea0fea8e52905d4b75 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Mon, 2 Nov 2026 22:00:29 -0800 Subject: [PATCH 3/4] test(ts): refresh the iters snapshot, and name call's receiver as #463 does Co-Authored-By: Claude Opus 5.5 --- ts/fixtures/lang/iters/expected/iters.ts | 4 ++-- ts/src/lower/iter.rs | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ts/fixtures/lang/iters/expected/iters.ts b/ts/fixtures/lang/iters/expected/iters.ts index fd38556f4..e75fa5fa3 100644 --- a/ts/fixtures/lang/iters/expected/iters.ts +++ b/ts/fixtures/lang/iters/expected/iters.ts @@ -9534,8 +9534,8 @@ export function lent(data: rt.ByteSlice, out: rt.ByteVec): void { rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(erased.next()), 238)); rt.iterExtendBytes(out, range, undefined, true); let boxed: rt.Iter = rt.iterDyn(rt.iterRev(rt.iterSlice(rt.byteSliceView(data)))); - rt.iterExtendBytes(out, rt.iterTake(rt.iterBorrow(boxed), n), "next"); - rt.iterExtendBytes(out, rt.iterTake(boxed, 1), "next"); + rt.iterExtendBytes(out, rt.iterTake(rt.iterBorrow(rt.iterBox(rt.iterBorrow(boxed))), n), "next"); + rt.iterExtendBytes(out, rt.iterTake(rt.iterBox(boxed), 1), "next"); const rest: rt.Iter = rt.iterSlice(rt.byteSliceView(data)); rt.iterExtendBytes(out, rt.byteVecIntoIter(halves$mut_iter_Copied_slice_Iter_u8(rest, n)), undefined, true); rt.iterExtendBytes(out, rest, undefined, true); diff --git a/ts/src/lower/iter.rs b/ts/src/lower/iter.rs index d57ef63ec..06834e2cb 100644 --- a/ts/src/lower/iter.rs +++ b/ts/src/lower/iter.rs @@ -630,9 +630,10 @@ pub fn call<'tcx>( not_bound(b, self_ty, span); let mut values = args.into_iter(); // What it reads through boxes and references, while std picks each specialization by - // `self_ty`, which a box implements none of. - let value = values.next()?; - let (iter_ty, recv) = peel_iter(b, self_ty, value.clone()); + // `self_ty`, which a box implements none of. `into_iter` peels `self_ty` itself, to tell + // a box apart. + let first = values.next()?; + let (iter_ty, recv) = peel_iter(b, self_ty, first.clone()); let rest: Vec = values.collect(); // What a consumer returns for `None`, after its other arguments, where that is `rt.None`. let none = b.t.none_arg(item); @@ -646,14 +647,14 @@ pub fn call<'tcx>( None => recv.member("nextBack").call(Vec::new()), }, _ => { - let recv = into_iter(b, self_ty, value, span)?; + let recv = into_iter(b, self_ty, first, span)?; let droppers = [b.t.dropper(item, span)].into_iter().chain(none).collect(); return Some(Expr::rt("iterNthBack", tail([vec![recv], rest].concat(), droppers))); } }; return Some(Expr::rt("iterToOption", [item].into_iter().chain(none).collect())); } - let recv = into_iter(b, self_ty, value, span)?; + let recv = into_iter(b, self_ty, first, span)?; // `rt.iter(recv, ...args)`, or `peekable` of a `Peekable`'s own. let method = |name: &str, args: Vec| { let of = match owner { From f1f5ee6c39857b1db3a920ba07b12c30880a561f Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Mon, 2 Nov 2026 22:07:32 -0800 Subject: [PATCH 4/4] fix(ts): forward a box's last where nothing drops too Co-Authored-By: Claude Opus 5.5 --- ts/fixtures/lang/dyns/expected/core/option.ts | 7 ++ ts/fixtures/lang/dyns/expected/dyns.ts | 81 ++++++++++++------- ts/fixtures/lang/dyns/src/dyns.rs | 16 ++++ ts/runtime/rt/iter.ts | 2 + 4 files changed, 75 insertions(+), 31 deletions(-) diff --git a/ts/fixtures/lang/dyns/expected/core/option.ts b/ts/fixtures/lang/dyns/expected/core/option.ts index 7f3f66121..39dfae595 100644 --- a/ts/fixtures/lang/dyns/expected/core/option.ts +++ b/ts/fixtures/lang/dyns/expected/core/option.ts @@ -68,6 +68,13 @@ export function map$0z7s8q7(self: [Tagged.Tagged, Tagged.Tagged] | undefined, f: return f(self); } +export function mapOr$1surhce(self: rt.u8 | undefined, default_: rt.u8, f: (a0: rt.u8) => rt.u8): rt.u8 { + if (self === undefined) { + return default_; + } + return f(self); +} + export function mapOr$1ttssgs(self: [rt.u8, rt.ByteSlice] | undefined, default_: [rt.u8, rt.ByteSlice], f: (a0: [rt.u8, rt.ByteSlice]) => [rt.u8, rt.ByteSlice]): [rt.u8, rt.ByteSlice] { if (self === undefined) { return default_; diff --git a/ts/fixtures/lang/dyns/expected/dyns.ts b/ts/fixtures/lang/dyns/expected/dyns.ts index 32a8699fe..a2d17c893 100644 --- a/ts/fixtures/lang/dyns/expected/dyns.ts +++ b/ts/fixtures/lang/dyns/expected/dyns.ts @@ -4,7 +4,7 @@ import * as rt from "./rt.ts"; import { drop$Result_Rc_dyns_Noisy_Rc_dyn_Any, drop$Result_Rc_dyns_Square_Rc_dyn_Any, drop$Result_Rc_dyns_Tri_Rc_dyn_Any, drop$tuple2_dyns_Tagged_dyns_Tagged, of$Option_u8, of$dyns_Hits, of$dyns_Lease, of$dyns_Looped, of$dyns_Noisy, of$dyns_Square, of$dyns_Tri, of$ref_str, of$tuple2_u8_u8, of$u32, of$u8, of$unit, ofPlace$Option_u8, ofPlace$dyns_Tri, ofPlace$u32, ofPlace$u8, ofPlace$unit } from "./lib.ts"; import type * as Any from "./core/any.Any.ts"; import { thenSome$0d5am30 } from "./core/bool.ts"; -import { isSomeAnd$13v37g1, unwrapOr$1iemzn8 as option_unwrapOr$1iemzn8, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$1i542n2 as option_map$1i542n2, map$0oedb57 as option_map$0oedb57, map$08a6hpg as option_map$08a6hpg, map$1qfllpb as option_map$1qfllpb, map$0j05j69 as option_map$0j05j69, map$0z7s8q7 as option_map$0z7s8q7, mapOr$1ttssgs as option_mapOr$1ttssgs, mapOr$06rr3sb as option_mapOr$06rr3sb, andThen$0v0bj8w as option_andThen$0v0bj8w, andThen$0ntiuws as option_andThen$0ntiuws } from "./core/option.ts"; +import { isSomeAnd$13v37g1, unwrapOr$1iemzn8 as option_unwrapOr$1iemzn8, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$1i542n2 as option_map$1i542n2, map$0oedb57 as option_map$0oedb57, map$08a6hpg as option_map$08a6hpg, map$1qfllpb as option_map$1qfllpb, map$0j05j69 as option_map$0j05j69, map$0z7s8q7 as option_map$0z7s8q7, mapOr$1surhce as option_mapOr$1surhce, mapOr$1ttssgs as option_mapOr$1ttssgs, mapOr$06rr3sb as option_mapOr$06rr3sb, andThen$0v0bj8w as option_andThen$0v0bj8w, andThen$0ntiuws as option_andThen$0ntiuws } from "./core/option.ts"; import { ok$00p9ap8, ok$1vbcgd7, ok$0lceojf, ok$1a014tb, map$1v8vvnp as result_map$1v8vvnp, map$1p3mw15 as result_map$1p3mw15, map$0zujxcv as result_map$0zujxcv } from "./core/result.ts"; import type * as Chunks from "./dyns.Chunks.ts"; import * as Countdown from "./dyns.Countdown.ts"; @@ -1380,10 +1380,10 @@ export function boxes(data: rt.ByteSlice, out: rt.ByteVec): void { const args8: rt.Fmt[] = [(f: rt.Formatter) => rt.usizeDisplay(part3, f)]; put(out, rt.fmtFormat([args8[0], " "])); dropped(out); - const sum: rt.u32 = rt.iterFold(rt.iterBox(it()), 0, (n2: rt.u32, _3: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { + const sum: rt.u32 = rt.iterFold(rt.iterBox(it()), 0, (n3: rt.u32, _3: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { const x: Tagged.Tagged = _3[0]; const y: Tagged.Tagged = _3[1]; - const _02: rt.u32 = rt.u32WrappingAdd(rt.u32WrappingMul(n2, 7), (x._0 ^ y._0) as rt.u32); + const _02: rt.u32 = rt.u32WrappingAdd(rt.u32WrappingMul(n3, 7), (x._0 ^ y._0) as rt.u32); y[Symbol.dispose](); x[Symbol.dispose](); return _02; @@ -1397,8 +1397,8 @@ export function boxes(data: rt.ByteSlice, out: rt.ByteVec): void { const arg = x2._0; const _142: rt.Fmt = (f: rt.Formatter) => rt.u8Display(arg, f); const arg2 = y2._0; - const args42: rt.Fmt[] = [_142, (f: rt.Formatter) => rt.u8Display(arg2, f)]; - put(out, rt.fmtFormat([args42[0], " ", args42[1], " "])); + const args44: rt.Fmt[] = [_142, (f: rt.Formatter) => rt.u8Display(arg2, f)]; + put(out, rt.fmtFormat([args44[0], " ", args44[1], " "])); y2[Symbol.dispose](); x2[Symbol.dispose](); }); @@ -1441,10 +1441,10 @@ export function boxes(data: rt.ByteSlice, out: rt.ByteVec): void { dropped(out); const args18: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtList(all, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; put(out, rt.fmtFormat([args18[0], " "])); - const back: rt.u32 = rt.iterFold(rt.iterRev(rt.iterBox(it())), 0, (n3: rt.u32, _33: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { + const back: rt.u32 = rt.iterFold(rt.iterRev(rt.iterBox(it())), 0, (n4: rt.u32, _33: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { const x5: Tagged.Tagged = _33[0]; const y3: Tagged.Tagged = _33[1]; - const _08: rt.u32 = rt.u32WrappingAdd(rt.u32WrappingMul(n3, 5), (x5._0 ^ y3._0) as rt.u32); + const _08: rt.u32 = rt.u32WrappingAdd(rt.u32WrappingMul(n4, 5), (x5._0 ^ y3._0) as rt.u32); y3[Symbol.dispose](); x5[Symbol.dispose](); return _08; @@ -1488,10 +1488,10 @@ export function boxes(data: rt.ByteSlice, out: rt.ByteVec): void { put(out, rt.fmtFormat([args28[0], " ", args28[1], " "])); const boxed4: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = it(); const first: [rt.u8, rt.u8] | undefined = tags(rt.iterToOption(boxed4.next())); - const sum2: rt.u32 = rt.iterFold(rt.iterBorrow(rt.iterBox(rt.iterBorrow(boxed4))), 0, (n4: rt.u32, _34: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { + const sum2: rt.u32 = rt.iterFold(rt.iterBorrow(rt.iterBox(rt.iterBorrow(boxed4))), 0, (n5: rt.u32, _34: [Tagged.Tagged, Tagged.Tagged]): rt.u32 => { const x7: Tagged.Tagged = _34[0]; const y5: Tagged.Tagged = _34[1]; - const _010: rt.u32 = rt.u32WrappingAdd(n4, (x7._0 ^ y5._0) as rt.u32); + const _010: rt.u32 = rt.u32WrappingAdd(n5, (x7._0 ^ y5._0) as rt.u32); y5[Symbol.dispose](); x7[Symbol.dispose](); return _010; @@ -1500,38 +1500,57 @@ export function boxes(data: rt.ByteSlice, out: rt.ByteVec): void { const args30: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(first, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.u32Display(sum2, f)]; put(out, rt.fmtFormat([args30[0], " ", args30[1], " "])); dropped(out); + const n2: rt.u8 = option_mapOr$1surhce(rt.byteSliceFirst(data), 0, (n6: rt.u8): rt.u8 => { + return rt.u8Rem(n6, 4); + }); + const seen: rt.RefCell = new rt.RefCell(new rt.ByteVec()); + const logged: () => rt.Iter<[rt.u8, rt.u8]> = (): rt.Iter<[rt.u8, rt.u8]> => { + return rt.iterZip(rt.iterMap(rt.iterChain(new rt.Range(0, n2), new rt.Range(n2, rt.u8Add(n2, 2))), (x8: rt.u8): rt.u8 => { + const _612: rt.RefCell = rt.refCellBorrowMut(seen); + rt.byteVecPush(_612.value, x8); + rt.refMutRelease(_612); + return x8; + }), new rt.Range(0, rt.u8Rem(n2, 3)), "len"); + }; + const last2: [rt.u8, rt.u8] | undefined = rt.iterLast(rt.iterBox(logged())); + const _351: [rt.u8, rt.u8] | undefined = rt.iterLast(rt.iterBorrow(rt.iterBox(rt.iterBorrow(logged())))); + const _354: rt.RefCell = rt.refCellBorrow(seen); + const args32: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(last2, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.fmtOption(_351, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.fmtList(rt.byteVecView(_354.value), f, rt.u8Debug)]; + const _347: string = rt.fmtFormat([args32[0], " ", args32[1], " ", args32[2], " "]); + rt.refRelease(_354); + put(out, _347); const part6 = tags(rt.ownedLast(rt.iterBox(rt.iterBorrow(skipped(data))), drop$tuple2_dyns_Tagged_dyns_Tagged)); - const args32: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part6, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; - put(out, rt.fmtFormat([args32[0], " "])); + const args34: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part6, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + put(out, rt.fmtFormat([args34[0], " "])); dropped(out); const part7 = rt.ownedCount(rt.iterBox(rt.iterBorrow(skipped(data))), drop$tuple2_dyns_Tagged_dyns_Tagged); - const args34: rt.Fmt[] = [(f: rt.Formatter) => rt.usizeDisplay(part7, f)]; - put(out, rt.fmtFormat([args34[0], " "])); + const args36: rt.Fmt[] = [(f: rt.Formatter) => rt.usizeDisplay(part7, f)]; + put(out, rt.fmtFormat([args36[0], " "])); dropped(out); const erased: () => rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = (): rt.Iter<[Tagged.Tagged, Tagged.Tagged]> => { return rt.iterDyn(skipped(data)); }; - const _378: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = rt.iterChain(rt.iterBox(erased()), rt.iterOption(undefined as [Tagged.Tagged, Tagged.Tagged] | undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); - const part8 = tags(rt.iterNth(_378, 1, drop$tuple2_dyns_Tagged_dyns_Tagged)); - const args36: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part8, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; - const _371: string = rt.fmtFormat([args36[0], " "]); - rt.drop(_378); - put(out, _371); + const _410: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = rt.iterChain(rt.iterBox(erased()), rt.iterOption(undefined as [Tagged.Tagged, Tagged.Tagged] | undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const part8 = tags(rt.iterNth(_410, 1, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args38: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part8, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + const _403: string = rt.fmtFormat([args38[0], " "]); + rt.drop(_410); + put(out, _403); dropped(out); - const _395: [rt.u8, rt.u8] | undefined = tags(rt.ownedLast(rt.iterBox(erased()), drop$tuple2_dyns_Tagged_dyns_Tagged)); - const _400: rt.usize = rt.ownedCount(rt.iterBox(erased()), drop$tuple2_dyns_Tagged_dyns_Tagged); - const args38: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(_395, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.usizeDisplay(_400, f)]; - put(out, rt.fmtFormat([args38[0], " ", args38[1], " "])); + const _427: [rt.u8, rt.u8] | undefined = tags(rt.ownedLast(rt.iterBox(erased()), drop$tuple2_dyns_Tagged_dyns_Tagged)); + const _432: rt.usize = rt.ownedCount(rt.iterBox(erased()), drop$tuple2_dyns_Tagged_dyns_Tagged); + const args40: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(_427, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f)), (f: rt.Formatter) => rt.usizeDisplay(_432, f)]; + put(out, rt.fmtFormat([args40[0], " ", args40[1], " "])); dropped(out); - const boxed5: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = erased(); - const _423: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = rt.iterChain(rt.iterBorrow(boxed5), rt.iterOption(undefined as [Tagged.Tagged, Tagged.Tagged] | undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); - const part9 = tags(rt.iterNth(_423, 1, drop$tuple2_dyns_Tagged_dyns_Tagged)); - const args40: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part9, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; - const _416: string = rt.fmtFormat([args40[0], " "]); - rt.drop(_423); - put(out, _416); + const boxed6: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = erased(); + const _455: rt.Iter<[Tagged.Tagged, Tagged.Tagged]> = rt.iterChain(rt.iterBorrow(boxed6), rt.iterOption(undefined as [Tagged.Tagged, Tagged.Tagged] | undefined, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const part9 = tags(rt.iterNth(_455, 1, drop$tuple2_dyns_Tagged_dyns_Tagged)); + const args42: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part9, f, (value: [rt.u8, rt.u8], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.u8Debug(value[1], f)], f))]; + const _448: string = rt.fmtFormat([args42[0], " "]); + rt.drop(_455); + put(out, _448); dropped(out); - rt.drop(boxed5); + rt.drop(boxed6); dropped(out); } diff --git a/ts/fixtures/lang/dyns/src/dyns.rs b/ts/fixtures/lang/dyns/src/dyns.rs index cf6969e35..b382db82e 100644 --- a/ts/fixtures/lang/dyns/src/dyns.rs +++ b/ts/fixtures/lang/dyns/src/dyns.rs @@ -1164,6 +1164,22 @@ pub fn boxes(data: &[u8], out: &mut Vec) { drop(boxed); dropped(out); + // Of items that never drop: `last` is still what the box holds, whose zip folds no more + // pairs than its size hint, where `next` reads its left side once more. + let n = data.first().map_or(0, |n| n % 4); + let seen = RefCell::new(Vec::new()); + let logged = || { + let seen = &seen; + let left = (0..n).chain(n..n + 2).map(move |x| { + seen.borrow_mut().push(x); + x + }); + Box::new(left.zip(0..n % 3)) + }; + let last = logged().last(); + let mut boxed = logged(); + put(out, &format!("{last:?} {:?} {:?} ", (&mut boxed).last(), seen.borrow())); + // A box of a `&mut`, whose `last` is the borrow's, which folds what it borrows. let mut held = skipped(data); put(out, &format!("{:?} ", tags(Box::new(&mut held).last()))); diff --git a/ts/runtime/rt/iter.ts b/ts/runtime/rt/iter.ts index 85db6a5fb..8cc62c037 100644 --- a/ts/runtime/rt/iter.ts +++ b/ts/runtime/rt/iter.ts @@ -908,6 +908,8 @@ export function iterCount(it: Iter): number { export function iterLast(it: Iter): T | undefined; export function iterLast(it: Iter, none: None): T | None; export function iterLast(it: Iter, none?: None): T | undefined | None { + // std's of a box: what it holds, by its own. + while (it instanceof Boxed) it = it.inner; const folded = it.folded(true); let last: T | Done = DONE; for (let item = folded.next(); item !== DONE; item = folded.next()) last = item;