diff --git a/quest/m2/ts-model/README.md b/quest/m2/ts-model/README.md index 0b67acd93..06b4b9d75 100644 --- a/quest/m2/ts-model/README.md +++ b/quest/m2/ts-model/README.md @@ -45,7 +45,7 @@ Decided with the maintainer on 2026-10-27, from a census of the model's 22 publi - The end-to-end work stays here: the model's roots, its differential harness, and the `frames.ts` workload. moq writes the binding files `model.toml` names, in its own tree. -The census at the pin on 2026-11-04: 69 refusals. `Timestamp` alone refuses nothing, and +The census at the pin on 2026-11-04: 82 refusals. `Timestamp` alone refuses nothing, and the [model fixture](/ts/README.md#tests)'s harness runs it against native moq-net at the pin; each case it adds as a type translates. Every other root reaches the rest of the model, so each child below unblocks all of them together. The rest is moq's, for its @@ -57,7 +57,6 @@ there, as does the `unsafe` slice of `model/frame.rs`'s `Filled`. ## Required -- [Iterators into a crate's own collections](/quest/m2/ts-model/from-iterator.md) - `collect`, `flat_map`, and `flatten` through moq-pattern's `Patterns` - [Bytes from an owner that drops](/quest/m2/ts-model/bytes-owner.md) - `Bytes::from_owner` of a frame's segment - [rangemap](/quest/m2/ts-model/rangemap.md) - B-tree ranges by a borrowed key, and std's iterators in a crate's fields - [Addresses as identity](/quest/m2/ts-model/addresses.md) - `Arc::as_ptr(a) as usize` as a key, which needs a decision diff --git a/quest/m2/ts-model/from-iterator.md b/quest/m2/ts-model/from-iterator.md deleted file mode 100644 index f437b1990..000000000 --- a/quest/m2/ts-model/from-iterator.md +++ /dev/null @@ -1,14 +0,0 @@ -# [S] Iterators into a crate's own collections - -## Goal - -[rust2-ts](/ts/README.md) translates std's iterator adaptors where a crate's own type is -the collection: `collect` into a type with a `FromIterator` impl, and `flat_map` and -`flatten` over a type with an `IntoIterator` impl, proven by differential tests against -native Rust, including drops and laziness. - -## Plan - -moq-pattern's `Patterns` reaches all three seven times at the pin, from moq-net's -`auth.rs` and `model/origin.rs` and from `Patterns::rebase` itself. The crate's impls -translate already; what is missing is std's adaptor calling them. diff --git a/ts/Cargo.lock b/ts/Cargo.lock index 716de715c..ea1392743 100644 --- a/ts/Cargo.lock +++ b/ts/Cargo.lock @@ -222,6 +222,10 @@ version = "0.0.0" name = "lang-collections-fixture" version = "0.0.0" +[[package]] +name = "lang-collects-fixture" +version = "0.0.0" + [[package]] name = "lang-combinators-fixture" version = "0.0.0" diff --git a/ts/README.md b/ts/README.md index dfe8e1ceb..1ad22f88b 100644 --- a/ts/README.md +++ b/ts/README.md @@ -389,6 +389,10 @@ each item's fields go into them in order, as `rs.tupleExtend(t, it, [rs.vecPart( rs.STRING_PART])`. The crate's own `Default + Extend` collection keeps the defaults stable Rust can't override: it reserves nothing, and takes each item by its `extend` of `Some(item)`, through `rs.ownPart`. Any other collection in one is refused. +The crate's own collection is collected by its own `FromIterator`, which `collect` and a +`collect` into a `Result` or an `Option` of it call with the iterator, as std's do, and std's +adaptors that take an `IntoIterator`, such as `flat_map`, `flatten`, `chain`, `zip`, and +`extend`, iterate it by its own `into_iter`. `clone` of one of std's iterators or adaptors is its `rs.Iter`'s `clone`, which reads on from where the original was, independently of it, as std's `Clone` does; one over a hash diff --git a/ts/fixtures/lang/collects/Cargo.toml b/ts/fixtures/lang/collects/Cargo.toml new file mode 100644 index 000000000..a8f892979 --- /dev/null +++ b/ts/fixtures/lang/collects/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "lang-collects-fixture" +description = "A part of the language rust2-ts translates, exercised against native Rust" +version = "0.0.0" +edition.workspace = true +license.workspace = true +publish = false + +[lib] +# The cdylib is the native side of the differential test, built for wasm32. +crate-type = ["lib", "cdylib"] + +[lints] +workspace = true diff --git a/ts/fixtures/lang/collects/expected/collects.Bag.ts b/ts/fixtures/lang/collects/expected/collects.Bag.ts new file mode 100644 index 000000000..22a74de35 --- /dev/null +++ b/ts/fixtures/lang/collects/expected/collects.Bag.ts @@ -0,0 +1,368 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Item from "./collects.Item.ts"; + +/** + * The crate's own collection, which reads its items only up to the first 0, dropping + * that one and leaving the rest in the iterator, which drops as `from_iter` returns. + */ +export class Bag { + items: rs.Vec; + + constructor(items: rs.Vec) { + this.items = items; + } + + [Symbol.dispose](): void { + rs.dropVec(this.items); + } +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Filter_iter_Rev_slice_Iter_u8_collects_collects_closure1_collects_collects_closure2(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Rev_slice_Iter_u8_collects_chains_closure2(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Skip_slice_Iter_u8_collects_chains_closure1(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Take_slice_Iter_u8_collects_chains_closure0(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_chains_closure3(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_collects_closure0(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_flattens_closure0_closure0(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_flattens_closure2_closure0(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_flattens_closure4_closure0(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_Skip_vec_IntoIter_collects_Item(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + const _0: Bag = new Bag(items); + rs.drop(iter2); + return _0; +} + +export function fromIter$iter_FromIterator_collects_Item_iter_adapters_GenericShunt_iter_Map_slice_Iter_u8_collects_collects_closure4_Result_never_u8(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function fromIter$iter_FromIterator_collects_Item_iter_adapters_GenericShunt_iter_Map_slice_Iter_u8_collects_collects_closure5_Option_never(iter: rs.Iter): Bag { + const iter2: rs.Iter = iter; + const items: rs.Vec = new rs.Vec(); + const iter3: rs.Iter = iter2; + while (true) { + const _8: Item.Item | rs.Done = iter3.next(); + if (_8 === rs.DONE) { + break; + } + const item: Item.Item = _8; + if (!(item.v === 0)) { + items.items.push(item); + } else { + item[Symbol.dispose](); + break; + } + } + const _17: Item.Item | undefined = rs.sliceFirst(rs.sliceFrom(items.items)); + if (_17 !== undefined) { + const _25: rs.RefCell> = rs.refCellBorrowMut(_17.log); + const part = items.items.length; + const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]); + _25.value.items.push(_26); + rs.refMutRelease(_25); + } + return new Bag(items); +} + +export function intoIter$iter_IntoIterator(self: Bag): rs.Iter { + return rs.vecIntoIter(self.items, rs.drop); +} + +export function intoIter$iter_IntoIterator_ref(self: Bag): rs.Iter { + return rs.iterSlice(self.items.items); +} + +//# sourceMappingURL=collects.Bag.ts.map diff --git a/ts/fixtures/lang/collects/expected/collects.Count.ts b/ts/fixtures/lang/collects/expected/collects.Count.ts new file mode 100644 index 000000000..de9bd14c4 --- /dev/null +++ b/ts/fixtures/lang/collects/expected/collects.Count.ts @@ -0,0 +1,21 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import * as Down from "./collects.Down.ts"; + +/** What counts down from `n`, by the crate's own iterator. */ +export interface Count { + n: rs.u8; + log: rs.RefCell>; +} + +export function intoIter$iter_IntoIterator(self: Count): Down.Down { + const _5: rs.RefCell> = rs.refCellBorrowMut(self.log); + const arg = self.n; + const _6: string = rs.fmtFormat(["count ", (f: rs.Formatter) => rs.u8Display(arg, f)]); + _5.value.items.push(_6); + rs.refMutRelease(_5); + return new Down.Down(self.n, self.log); +} + +//# sourceMappingURL=collects.Count.ts.map diff --git a/ts/fixtures/lang/collects/expected/collects.Down.ts b/ts/fixtures/lang/collects/expected/collects.Down.ts new file mode 100644 index 000000000..7274f72f7 --- /dev/null +++ b/ts/fixtures/lang/collects/expected/collects.Down.ts @@ -0,0 +1,42 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** The crate's own iterator, which logs each read and its drop. */ +export class Down { + n: rs.u8; + log: rs.RefCell>; + + constructor(n: rs.u8, log: rs.RefCell>) { + this.n = n; + this.log = log; + } + + [Symbol.dispose](): void { + drop$ops_Drop(this); + } +} + +export function next$iter_Iterator(self: Down): rs.u8 | rs.Done { + const _5: rs.RefCell> = rs.refCellBorrowMut(self.log); + const arg = self.n; + const _6: string = rs.fmtFormat(["next ", (f: rs.Formatter) => rs.u8Display(arg, f)]); + _5.value.items.push(_6); + rs.refMutRelease(_5); + const _15: rs.u8 | undefined = rs.u8CheckedSub(self.n, 1); + if (_15 !== undefined) { + self.n = _15; + return self.n; + } + return rs.DONE; +} + +export function drop$ops_Drop(self: Down): void { + const _5: rs.RefCell> = rs.refCellBorrowMut(self.log); + const arg = self.n; + const _6: string = rs.fmtFormat(["down dropped at ", (f: rs.Formatter) => rs.u8Display(arg, f)]); + _5.value.items.push(_6); + rs.refMutRelease(_5); +} + +//# sourceMappingURL=collects.Down.ts.map diff --git a/ts/fixtures/lang/collects/expected/collects.Item.ts b/ts/fixtures/lang/collects/expected/collects.Item.ts new file mode 100644 index 000000000..b60b3d9d8 --- /dev/null +++ b/ts/fixtures/lang/collects/expected/collects.Item.ts @@ -0,0 +1,28 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** Logs its byte as it drops. */ +export class Item { + v: rs.u8; + log: rs.RefCell>; + + constructor(v: rs.u8, log: rs.RefCell>) { + this.v = v; + this.log = log; + } + + [Symbol.dispose](): void { + drop$ops_Drop(this); + } +} + +export function drop$ops_Drop(self: Item): void { + const _5: rs.RefCell> = rs.refCellBorrowMut(self.log); + const arg = self.v; + const _6: string = rs.fmtFormat(["drop ", (f: rs.Formatter) => rs.u8Display(arg, f)]); + _5.value.items.push(_6); + rs.refMutRelease(_5); +} + +//# sourceMappingURL=collects.Item.ts.map diff --git a/ts/fixtures/lang/collects/expected/collects.Stack.ts b/ts/fixtures/lang/collects/expected/collects.Stack.ts new file mode 100644 index 000000000..c0dc36d81 --- /dev/null +++ b/ts/fixtures/lang/collects/expected/collects.Stack.ts @@ -0,0 +1,49 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import * as Down from "./collects.Down.ts"; +import type * as Item from "./collects.Item.ts"; + +/** + * The crate's own collection of any type, which keeps its items in reverse and counts + * them, so a `collect` that skipped it would differ. + */ +export class Stack { + items: rs.VecOf; + count: rs.usize; + + constructor(items: rs.VecOf, count: rs.usize) { + this.items = items; + this.count = count; + } + + [Symbol.dispose](): void { + rs.dropVec(this.items as rs.Vec); + } +} + +export function fromIter$iter_FromIterator_collects_Item_collects_Item_iter_Map_iter_Take_slice_Iter_u8_collects_collects_closure8(iter: rs.Iter): Stack { + const items: rs.Vec = rs.iterToVec(iter, undefined, 8, true); + rs.sliceReverse(rs.sliceFrom(items.items)); + return new Stack(items, items.items.length); +} + +export function fromIter$iter_FromIterator_u16_u16_iter_Map_slice_Iter_u8_collects_collects_closure7(iter: rs.Iter): Stack { + const items: rs.Vec = rs.iterToVec(iter, undefined, 2, true); + rs.sliceReverse(rs.sliceFrom(items.items)); + return new Stack(items, items.items.length); +} + +export function fromIter$iter_FromIterator_u8_u8_collects_Down(iter: Down.Down): Stack { + const items: rs.ByteVec = rs.iterToByteVec(rs.iterFrom(iter, Down.next$iter_Iterator, rs.drop), "next"); + rs.byteSliceView(rs.byteVecSlice(items)).reverse(); + return new Stack(items, items.length); +} + +export function fromIter$iter_FromIterator_u8_u8_iter_Take_mut_collects_Down(iter: rs.Iter): Stack { + const items: rs.ByteVec = rs.iterToByteVec(iter, "next"); + rs.byteSliceView(rs.byteVecSlice(items)).reverse(); + return new Stack(items, items.length); +} + +//# sourceMappingURL=collects.Stack.ts.map diff --git a/ts/fixtures/lang/collects/expected/collects.Tries.ts b/ts/fixtures/lang/collects/expected/collects.Tries.ts new file mode 100644 index 000000000..e08bd553e --- /dev/null +++ b/ts/fixtures/lang/collects/expected/collects.Tries.ts @@ -0,0 +1,36 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Item from "./collects.Item.ts"; + +/** + * The crate's own collection of the first three reads of its iterator, which reads on past + * a `None`, as nothing stops it from doing. + */ +export class Tries { + _0: rs.Vec; + + constructor(_0: rs.Vec) { + this._0 = _0; + } + + [Symbol.dispose](): void { + rs.dropVec(this._0); + } +} + +export function fromIter$iter_FromIterator_collects_Item_collects_Item_iter_adapters_GenericShunt_iter_Map_slice_Iter_u8_collects_collects_closure11_Option_never(iter: rs.Iter): Tries { + const iter2: rs.Iter = iter; + return new Tries(rs.iterToVec(rs.iterMap(new rs.Range(0, 3), (_2: rs.i32): Item.Item | undefined => { + return rs.iterToOption(iter2.next()); + }), undefined, 8, true)); +} + +export function fromIter$iter_FromIterator_u8_u8_iter_adapters_GenericShunt_iter_Map_slice_Iter_u8_collects_collects_closure10_Result_never_collects_Item(iter: rs.Iter): Tries { + const iter2: rs.Iter = iter; + return new Tries(rs.iterToVec(rs.iterMap(new rs.Range(0, 3), (_2: rs.i32): rs.u8 | undefined => { + return rs.iterToOption(iter2.next()); + }), undefined, 2, true)); +} + +//# sourceMappingURL=collects.Tries.ts.map diff --git a/ts/fixtures/lang/collects/expected/collects.ts b/ts/fixtures/lang/collects/expected/collects.ts new file mode 100644 index 000000000..770453d88 --- /dev/null +++ b/ts/fixtures/lang/collects/expected/collects.ts @@ -0,0 +1,371 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import * as Bag from "./collects.Bag.ts"; +import * as Count from "./collects.Count.ts"; +import * as Down from "./collects.Down.ts"; +import * as Item from "./collects.Item.ts"; +import * as Stack from "./collects.Stack.ts"; +import * as Tries from "./collects.Tries.ts"; +import { then$0bmzd6l } from "./core/bool.ts"; +import { map$1hm93qk as option_map$1hm93qk, map$1yttib1 as option_map$1yttib1, map$0a0rmxp as option_map$0a0rmxp, mapOr$0vxw5sq as option_mapOr$0vxw5sq } from "./core/option.ts"; +import { put } from "./harness.ts"; + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$Option_ref_collects_Item(out: rs.ByteVec, log: rs.RefCell>, values: Item.Item | undefined): void { + const part = rs.iterToByteVec(rs.iterMap(rs.iterOption(values), (item: Item.Item): rs.u8 => { + return item.v; + }), undefined, true); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$array0_ref_collects_Item(out: rs.ByteVec, log: rs.RefCell>, values: Item.Item[]): void { + const part = rs.iterToByteVec(rs.iterMap(rs.iterSlice(values), (item: Item.Item): rs.u8 => { + return item.v; + }), undefined, true); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$iter_Chain_slice_Iter_collects_Item_slice_Iter_collects_Item(out: rs.ByteVec, log: rs.RefCell>, values: rs.Iter): void { + const part = rs.iterToByteVec(rs.iterMap(values, (item: Item.Item): rs.u8 => { + return item.v; + }), undefined, true); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$iter_Flatten_option_Iter_collects_Bag(out: rs.ByteVec, log: rs.RefCell>, values: rs.Iter): void { + const part = rs.iterToByteVec(rs.iterMap(values, (item: Item.Item): rs.u8 => { + return item.v; + }), "next"); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$iter_Skip_iter_Flatten_slice_Iter_collects_Bag(out: rs.ByteVec, log: rs.RefCell>, values: rs.Iter): void { + const part = rs.iterToByteVec(rs.iterMap(values, (item: Item.Item): rs.u8 => { + return item.v; + }), "next"); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$iter_StepBy_iter_FlatMap_iter_Rev_ops_Range_usize_ref_collects_Bag_collects_flattens_closure5(out: rs.ByteVec, log: rs.RefCell>, values: rs.Iter): void { + const part = rs.iterToByteVec(rs.iterMap(values, (item: Item.Item): rs.u8 => { + return item.v; + }), "next"); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$iter_Take_slice_Iter_collects_Item(out: rs.ByteVec, log: rs.RefCell>, values: rs.Iter): void { + const part = rs.iterToByteVec(rs.iterMap(values, (item: Item.Item): rs.u8 => { + return item.v; + }), undefined, true); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$ref_Vec_collects_Item(out: rs.ByteVec, log: rs.RefCell>, values: rs.Vec): void { + const part = rs.iterToByteVec(rs.iterMap(rs.iterSlice(values.items), (item: Item.Item): rs.u8 => { + return item.v; + }), undefined, true); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** What `values` reads, each at most `limit`, and the log. */ +export function write$ref_collects_Bag(out: rs.ByteVec, log: rs.RefCell>, values: Bag.Bag): void { + const part = rs.iterToByteVec(rs.iterMap(Bag.intoIter$iter_IntoIterator_ref(values), (item: Item.Item): rs.u8 => { + return item.v; + }), undefined, true); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part), f, rs.u8Debug)])); + const _29: rs.RefCell> = rs.refCellBorrowMut(log); + put(out, rs.strsJoin(rs.iterToVec(rs.vecDrain(_29.value, undefined), "fold", 12, true).items, ", ")); + rs.refMutRelease(_29); +} + +/** + * `collect` into the crate's collections, which read their source lazily up to its first + * 0, and into a `Result` or an `Option` of one, which stops at its first `Err` or `None`. + */ +export function collects(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { + const log: rs.RefCell> = new rs.RefCell(new rs.Vec()); + const item: (a0: rs.u8) => Item.Item = (v: rs.u8): Item.Item => { + const _6: rs.RefCell> = rs.refCellBorrowMut(log); + const _7: string = rs.fmtFormat(["make ", (f: rs.Formatter) => rs.u8Display(v, f)]); + _6.value.items.push(_7); + rs.refMutRelease(_6); + return new Item.Item(v, log); + }; + const k: rs.usize = kind >> 3 as rs.usize; + const _12: rs.u8 = rs.u8Rem(kind, 8); + if (_12 === 0) { + const bag: Bag.Bag = Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_collects_closure0(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_218: rs.u8): Item.Item => { + return item(_218); + })); + write$ref_collects_Bag(out, log, bag); + bag[Symbol.dispose](); + } else if (_12 === 1) { + const bag2: Bag.Bag = Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Filter_iter_Rev_slice_Iter_u8_collects_collects_closure1_collects_collects_closure2(rs.iterMap(rs.iterFilter(rs.iterRev(rs.iterSlice(rs.byteSliceView(data))), (_216: rs.u8): boolean => { + return rs.u8Rem(_216, 3) !== 1; + }), (_217: rs.u8): Item.Item => { + return item(_217); + })); + const _31: rs.Iter = rs.iterTake(rs.iterSlice(bag2.items.items), k); + write$iter_Take_slice_Iter_collects_Item(out, log, _31); + bag2[Symbol.dispose](); + } else if (_12 === 2) { + const bag3: Bag.Bag = Bag.fromIter$iter_FromIterator_collects_Item_iter_Skip_vec_IntoIter_collects_Item(rs.iterSkip(rs.vecIntoIter(rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_215: rs.u8): Item.Item => { + return item(_215); + }), undefined, 8, true), rs.drop), k, rs.drop)); + write$ref_collects_Bag(out, log, bag3); + bag3[Symbol.dispose](); + } else if (_12 === 3) { + const bag4: rs.Result = rs.iterCollectResult(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_214: rs.u8): rs.Result => { + const v8: rs.u8 = _214; + if (!(240 <= v8)) { + return rs.Ok(item(v8)); + } + return rs.Err(v8); + }), (values: rs.Iter) => Bag.fromIter$iter_FromIterator_collects_Item_iter_adapters_GenericShunt_iter_Map_slice_Iter_u8_collects_collects_closure4_Result_never_u8(values), rs.drop); + if (bag4.ok) { + const bag5: Bag.Bag = bag4.value; + write$ref_collects_Bag(out, log, bag5); + bag5[Symbol.dispose](); + } else { + const arg5 = bag4.error; + put(out, rs.fmtFormat(["err ", (f: rs.Formatter) => rs.u8Display(arg5, f)])); + } + } else if (_12 === 4) { + const bag6: Bag.Bag | undefined = rs.iterCollectOption(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_212: rs.u8): Item.Item | undefined => { + const v7: rs.u8 = _212; + return then$0bmzd6l(v7 < 240, (): Item.Item => { + return item(v7); + }); + }), (values: rs.Iter) => Bag.fromIter$iter_FromIterator_collects_Item_iter_adapters_GenericShunt_iter_Map_slice_Iter_u8_collects_collects_closure5_Option_never(values), rs.drop); + const part6 = option_map$0a0rmxp(bag6, (bag7: Bag.Bag): rs.usize => { + return bag7.items.items.length; + }); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtOption(part6, f, rs.usizeDebug)])); + const _89: rs.Iter = rs.iterFlatten(rs.iterOption(bag6), (value: Bag.Bag) => Bag.intoIter$iter_IntoIterator_ref(value), true); + write$iter_Flatten_option_Iter_collects_Bag(out, log, _89); + rs.drop(bag6); + } else if (_12 === 5) { + const stack: Stack.Stack = Stack.fromIter$iter_FromIterator_u16_u16_iter_Map_slice_Iter_u8_collects_collects_closure7(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_210: rs.u8): rs.u16 => { + return rs.u16Mul(_210 as rs.u16, 3); + })); + const part5 = stack.items as rs.Vec; + const _105: rs.Fmt = (f: rs.Formatter) => rs.fmtList(part5.items, f, rs.u16Debug); + const arg4 = stack.count; + const args25 = [_105, (f: rs.Formatter) => rs.usizeDisplay(arg4, f)]; + put(out, rs.fmtFormat([args25[0], " ", args25[1]])); + const stack2: Stack.Stack = Stack.fromIter$iter_FromIterator_collects_Item_collects_Item_iter_Map_iter_Take_slice_Iter_u8_collects_collects_closure8(rs.iterMap(rs.iterTake(rs.iterSlice(rs.byteSliceView(data)), k), (_211: rs.u8): Item.Item => { + return item(_211); + })); + write$ref_Vec_collects_Item(out, log, stack2.items as rs.Vec); + stack2[Symbol.dispose](); + } else if (_12 === 6) { + const n: rs.u8 = option_mapOr$0vxw5sq(rs.byteSliceFirst(data), 0, (v4: rs.u8): rs.u8 => { + return rs.u8Rem(v4, 9); + }); + const stack3: Stack.Stack = Stack.fromIter$iter_FromIterator_u8_u8_collects_Down(new Down.Down(n, log)); + const part3 = stack3.items as rs.ByteVec; + const _133: rs.Fmt = (f: rs.Formatter) => rs.fmtList(rs.byteVecView(part3), f, rs.u8Debug); + const arg2 = stack3.count; + const args23 = [_133, (f: rs.Formatter) => rs.usizeDisplay(arg2, f)]; + put(out, rs.fmtFormat([args23[0], " ", args23[1]])); + const down: Down.Down = new Down.Down(n, log); + const stack4: Stack.Stack = Stack.fromIter$iter_FromIterator_u8_u8_iter_Take_mut_collects_Down(rs.iterTake(rs.iterFrom(down, Down.next$iter_Iterator), k)); + const _153: rs.u8 | undefined = rs.iterToOption(Down.next$iter_Iterator(down)); + const part4 = stack4.items as rs.ByteVec; + const _156: rs.Fmt = (f: rs.Formatter) => rs.fmtList(rs.byteVecView(part4), f, rs.u8Debug); + const arg3 = stack4.count; + const args24 = [_156, (f: rs.Formatter) => rs.usizeDisplay(arg3, f), (f: rs.Formatter) => rs.fmtOption(_153, f, rs.u8Debug)]; + put(out, rs.fmtFormat([args24[0], " ", args24[1], " ", args24[2]])); + down[Symbol.dispose](); + } else { + const tries: rs.Result, Item.Item> = rs.iterCollectResult(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_2: rs.u8): rs.Result => { + const v2: rs.u8 = _2; + if (!(rs.u8Rem(v2, 3) === 0)) { + return rs.Ok(v2); + } + return rs.Err(item(v2)); + }), (values: rs.Iter) => Tries.fromIter$iter_FromIterator_u8_u8_iter_adapters_GenericShunt_iter_Map_slice_Iter_u8_collects_collects_closure10_Result_never_collects_Item(values), undefined, rs.drop); + if (tries.ok) { + const part = tries.value._0; + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(part.items, f, (value: rs.u8 | undefined, f: rs.Formatter) => rs.fmtOption(value, f, rs.u8Debug))])); + } else { + const e2: Item.Item = tries.error; + const arg = e2.v; + put(out, rs.fmtFormat(["err ", (f: rs.Formatter) => rs.u8Display(arg, f)])); + e2[Symbol.dispose](); + } + const part2 = option_map$1yttib1(rs.iterCollectOption(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_22: rs.u8): Item.Item | undefined => { + const v3: rs.u8 = _22; + return then$0bmzd6l(rs.u8Rem(v3, 3) !== 0, (): Item.Item => { + return item(v3); + }); + }), (values: rs.Iter) => Tries.fromIter$iter_FromIterator_collects_Item_collects_Item_iter_adapters_GenericShunt_iter_Map_slice_Iter_u8_collects_collects_closure11_Option_never(values), rs.drop), (_29: Tries.Tries): rs.Vec => { + const values3: rs.Vec = _29._0; + const _05: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(values3.items), (item2: Item.Item | undefined): rs.u8 | undefined => { + return option_map$1hm93qk(item2, (item3: Item.Item): rs.u8 => { + return item3.v; + }); + }), undefined, 2, true); + rs.dropVec(values3); + return _05; + }); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtOption(part2, f, (value: rs.Vec, f: rs.Formatter) => rs.fmtList(value.items, f, (value: rs.u8 | undefined, f: rs.Formatter) => rs.fmtOption(value, f, rs.u8Debug)))])); + } + write$array0_ref_collects_Item(out, log, []); +} + +/** + * `flat_map` and `flatten` over the crate's collections, by value and by reference, and + * over one whose iterator is the crate's own, read only so far. + */ +export function flattens(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { + const log: rs.RefCell> = new rs.RefCell(new rs.Vec()); + const item: (a0: rs.u8) => Item.Item = (v: rs.u8): Item.Item => { + const _6: rs.RefCell> = rs.refCellBorrowMut(log); + const _7: string = rs.fmtFormat(["make ", (f: rs.Formatter) => rs.u8Display(v, f)]); + _6.value.items.push(_7); + rs.refMutRelease(_6); + return new Item.Item(v, log); + }; + const k: rs.usize = kind >> 3 as rs.usize; + const _11: rs.u8 = rs.u8Rem(kind, 8); + if (_11 === 0) { + const it: rs.Iter = rs.iterFlatMap(rs.byteSliceChunks(data, 3), (chunk3: rs.ByteSlice): Bag.Bag => { + return Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_flattens_closure0_closure0(rs.iterMap(rs.iterSlice(rs.byteSliceView(chunk3)), (_28: rs.u8): Item.Item => { + return item(_28); + })); + }, (value: Bag.Bag) => Bag.intoIter$iter_IntoIterator(value), true); + const front: rs.Vec = rs.iterToVec(rs.iterTake(rs.iterBorrow(it), k, rs.drop), "next", 8); + const back: rs.u8 | undefined = option_map$1hm93qk(rs.iterToOption(it.nextBack()), (item3: Item.Item): rs.u8 => { + const _013: rs.u8 = item3.v; + item3[Symbol.dispose](); + return _013; + }); + const _27: rs.RefCell> = rs.refCellBorrowMut(log); + const _29: string = rs.fmtFormat(["back ", (f: rs.Formatter) => rs.fmtOption(back, f, rs.u8Debug)]); + _27.value.items.push(_29); + rs.refMutRelease(_27); + rs.drop(it); + write$ref_Vec_collects_Item(out, log, front); + rs.dropVec(front); + } else if (_11 === 1) { + const bags: rs.Vec = rs.iterToVec(rs.iterMap(rs.byteSliceChunks(data, 2), (chunk2: rs.ByteSlice): Bag.Bag => { + return Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_flattens_closure2_closure0(rs.iterMap(rs.iterSlice(rs.byteSliceView(chunk2)), (_26: rs.u8): Item.Item => { + return item(_26); + })); + }), undefined, 12, true); + const _50: rs.Iter = rs.iterSkip(rs.iterFlatten(rs.iterSlice(bags.items), (value: Bag.Bag) => Bag.intoIter$iter_IntoIterator_ref(value), true), k); + write$iter_Skip_iter_Flatten_slice_Iter_collects_Bag(out, log, _50); + const _57: rs.Iter = rs.iterFlatten(rs.vecIntoIter(bags, rs.drop), (value: Bag.Bag) => Bag.intoIter$iter_IntoIterator(value), true); + const found: Item.Item | undefined = rs.iterFind(_57, (item2: Item.Item): boolean => { + return (item2.v as rs.usize) === k; + }, rs.drop); + rs.drop(_57); + write$Option_ref_collects_Item(out, log, found); + rs.drop(found); + } else if (_11 === 2) { + const bags2: rs.Vec = rs.iterToVec(rs.iterMap(rs.byteSliceChunks(data, 2), (chunk: rs.ByteSlice): Bag.Bag => { + return Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_flattens_closure4_closure0(rs.iterMap(rs.iterSlice(rs.byteSliceView(chunk)), (_24: rs.u8): Item.Item => { + return item(_24); + })); + }), undefined, 12, true); + const _72: rs.Iter = rs.iterStepBy(rs.iterFlatMap(rs.iterRev(new rs.Range(0, bags2.items.length)), (i: rs.usize): Bag.Bag => { + return bags2.items[rs.idx(bags2.items, i)]; + }, (value: Bag.Bag) => Bag.intoIter$iter_IntoIterator_ref(value), true), rs.usizeAdd(k, 1)); + write$iter_StepBy_iter_FlatMap_iter_Rev_ops_Range_usize_ref_collects_Bag_collects_flattens_closure5(out, log, _72); + rs.dropVec(bags2); + } else if (_11 === 3) { + const part2 = rs.iterToByteVec(rs.iterTake(rs.iterFlatMap(rs.iterSlice(rs.byteSliceView(data)), (_23: rs.u8): Count.Count => { + return { n: rs.u8Rem(_23, 5), log }; + }, (value: Count.Count) => rs.iterFrom(Count.intoIter$iter_IntoIterator(value), Down.next$iter_Iterator, rs.drop), true), k), "next"); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part2), f, rs.u8Debug)])); + } else if (_11 === 4) { + const part = rs.iterFold(rs.iterFlatten(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_2: rs.u8): Count.Count => { + return { n: rs.u8Rem(_2, 4), log }; + }), (value: Count.Count) => rs.iterFrom(Count.intoIter$iter_IntoIterator(value), Down.next$iter_Iterator, rs.drop), true), 0, (sum2: rs.u32, v3: rs.u8): rs.u32 => { + return rs.u32Add(sum2, v3 as rs.u32); + }, true); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.u32Display(part, f)])); + } + write$array0_ref_collects_Item(out, log, []); +} + +/** `chain`, `zip`, and `extend` of the crate's collections. */ +export function chains(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { + const log: rs.RefCell> = new rs.RefCell(new rs.Vec()); + const item: (a0: rs.u8) => Item.Item = (v: rs.u8): Item.Item => { + const _6: rs.RefCell> = rs.refCellBorrowMut(log); + const _7: string = rs.fmtFormat(["make ", (f: rs.Formatter) => rs.u8Display(v, f)]); + _6.value.items.push(_7); + rs.refMutRelease(_6); + return new Item.Item(v, log); + }; + const k: rs.usize = kind >> 1 as rs.usize; + if (rs.u8Rem(kind, 2) === 0) { + const bag: Bag.Bag = Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Take_slice_Iter_u8_collects_chains_closure0(rs.iterMap(rs.iterTake(rs.iterSlice(rs.byteSliceView(data)), k), (_26: rs.u8): Item.Item => { + return item(_26); + })); + const other: Bag.Bag = Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Skip_slice_Iter_u8_collects_chains_closure1(rs.iterMap(rs.iterSkip(rs.iterSlice(rs.byteSliceView(data)), k), (_210: rs.u8): Item.Item => { + return item(_210); + })); + const _27: rs.Iter = rs.iterChain(rs.iterSlice(bag.items.items), Bag.intoIter$iter_IntoIterator_ref(other)); + write$iter_Chain_slice_Iter_collects_Item_slice_Iter_collects_Item(out, log, _27); + const items: rs.Vec = rs.iterToVec(rs.iterChain(Bag.intoIter$iter_IntoIterator(bag), Bag.intoIter$iter_IntoIterator(other)), "fold", 8, true); + const more: Bag.Bag = Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Rev_slice_Iter_u8_collects_chains_closure2(rs.iterMap(rs.iterRev(rs.iterSlice(rs.byteSliceView(data))), (_211: rs.u8): Item.Item => { + return item(_211); + })); + rs.iterExtend(items, Bag.intoIter$iter_IntoIterator(more), "fold", 8, true); + write$ref_Vec_collects_Item(out, log, items); + rs.dropVec(items); + } else { + const bag2: Bag.Bag = Bag.fromIter$iter_FromIterator_collects_Item_iter_Map_slice_Iter_u8_collects_chains_closure3(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_2: rs.u8): Item.Item => { + return item(_2); + })); + const part = rs.iterToVec(rs.iterMap(rs.iterZip(rs.iterSlice(rs.byteSliceView(data)), rs.iterFrom(Count.intoIter$iter_IntoIterator({ n: 4, log }), Down.next$iter_Iterator, rs.drop)), (_24: [rs.u8, rs.u8]): [rs.u8, rs.u8] => { + return [_24[0], _24[1]] as [rs.u8, rs.u8]; + }), "next", 2); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(part.items, f, (value: [rs.u8, rs.u8], f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(value[0], f), (f: rs.Formatter) => rs.u8Debug(value[1], f)], f))])); + const part2 = rs.iterToByteVec(rs.iterMap(rs.iterZip(new rs.Range(0, k), Bag.intoIter$iter_IntoIterator(bag2), "len", undefined, rs.drop), (_25: [rs.usize, Item.Item]): rs.u8 => { + const item2: Item.Item = _25[1]; + const _04: rs.u8 = item2.v; + item2[Symbol.dispose](); + return _04; + }), "fold", true); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(part2), f, rs.u8Debug)])); + } + write$array0_ref_collects_Item(out, log, []); +} + +//# sourceMappingURL=collects.ts.map diff --git a/ts/fixtures/lang/collects/expected/core/bool.ts b/ts/fixtures/lang/collects/expected/core/bool.ts new file mode 100644 index 000000000..65738a9fe --- /dev/null +++ b/ts/fixtures/lang/collects/expected/core/bool.ts @@ -0,0 +1,12 @@ +// Generated by rust2-ts. Do not edit. + +import type * as Item from "../collects.Item.ts"; + +export function then$0bmzd6l(self: boolean, f: () => Item.Item): Item.Item | undefined { + if (!self) { + return undefined; + } + return f(); +} + +//# sourceMappingURL=bool.ts.map diff --git a/ts/fixtures/lang/collects/expected/core/option.ts b/ts/fixtures/lang/collects/expected/core/option.ts new file mode 100644 index 000000000..1a98e08bd --- /dev/null +++ b/ts/fixtures/lang/collects/expected/core/option.ts @@ -0,0 +1,36 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "../rs.ts"; +import type * as Bag from "../collects.Bag.ts"; +import type * as Item from "../collects.Item.ts"; +import type * as Tries from "../collects.Tries.ts"; + +export function map$1hm93qk(self: Item.Item | undefined, f: (a0: Item.Item) => rs.u8): rs.u8 | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1yttib1(self: Tries.Tries | undefined, f: (a0: Tries.Tries) => rs.Vec): rs.Vec | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$0a0rmxp(self: Bag.Bag | undefined, f: (a0: Bag.Bag) => rs.usize): rs.usize | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function mapOr$0vxw5sq(self: rs.u8 | undefined, default_: rs.u8, f: (a0: rs.u8) => rs.u8): rs.u8 { + if (self === undefined) { + return default_; + } + return f(self); +} + +//# sourceMappingURL=option.ts.map diff --git a/ts/fixtures/lang/collects/expected/harness.ts b/ts/fixtures/lang/collects/expected/harness.ts new file mode 100644 index 000000000..d3614fb27 --- /dev/null +++ b/ts/fixtures/lang/collects/expected/harness.ts @@ -0,0 +1,44 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import { cases } from "./lib.ts"; + +/** Run one case. */ +export function run(input: rs.ByteSlice): rs.ByteVec { + const out: rs.ByteVec = new rs.ByteVec(); + if (!(input.length >= 3)) { + return out; + } + const cases_: rs.Vec<[string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]> = cases(); + cases_.items[rs.idx(cases_.items, rs.usizeRem(((input.data[input.start] << 8) | input.data[input.start + 1]) as rs.usize, cases_.items.length))][1](input.data[input.start + 2], new rs.ByteSlice(input.data, input.start + 3, input.length - 3), out); + return out; +} + +/** + * The first two bytes, as one big-endian number, that pick the case named `name`, which + * `lang.ts` targets by. + */ +export function op(name: string): rs.u16 { + const _11: rs.usize | undefined = rs.iterPosition(rs.iterSlice(cases().items), (_2: [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]): boolean => { + return _2[0] === name; + }); + if (_11 !== undefined) { + const _20: rs.Result = rs.u16TryFrom(_11); + if (_20.ok) { + if ((_20.value >> 8) !== 255) { + return _20.value; + } + } + rs.panicFmt(["case ", (f: rs.Formatter) => rs.fmtPad(f, name), " is past what two bytes pick"]); + } else { + rs.panicFmt(["no case ", (f: rs.Formatter) => rs.fmtPad(f, name)]); + } +} + +/** Write `s` and the byte no UTF-8 holds, which ends it. */ +export function put(out: rs.ByteVec, s: string): void { + rs.byteVecExtendFromSlice(out, rs.stringAsBytes(s)); + rs.byteVecPush(out, 255); +} + +//# sourceMappingURL=harness.ts.map diff --git a/ts/fixtures/lang/collects/expected/lib.ts b/ts/fixtures/lang/collects/expected/lib.ts new file mode 100644 index 000000000..ac3ae47b0 --- /dev/null +++ b/ts/fixtures/lang/collects/expected/lib.ts @@ -0,0 +1,14 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import { collects, flattens, chains } from "./collects.ts"; + +/** + * Each case's name and what it runs. The first two bytes, big-endian, pick one modulo + * their count, so a case added at the end moves no other. + */ +export function cases(): rs.Vec<[string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]> { + return rs.vecFrom([["collects::collects", collects as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["collects::flattens", flattens as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["collects::chains", chains as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]]); +} + +//# sourceMappingURL=lib.ts.map diff --git a/ts/fixtures/lang/collects/src/collects.rs b/ts/fixtures/lang/collects/src/collects.rs new file mode 100644 index 000000000..1fdb11a8b --- /dev/null +++ b/ts/fixtures/lang/collects/src/collects.rs @@ -0,0 +1,313 @@ +//! The crate's own collections, which std's adaptors reach by their `FromIterator` and +//! `IntoIterator` impls: `collect`, and `collect` into a `Result` or an `Option` of one; +//! `flat_map` and `flatten` over them, by value and by reference, and over one whose +//! iterator is the crate's own; and `chain`, `zip`, and `Vec::extend` of one. Each item +//! logs as it is made, read, and dropped, so the log shows what each reads, how far, and +//! when what it left drops. + +use std::cell::RefCell; + +use crate::harness::put; + +type Log = RefCell>; + +/// Logs its byte as it drops. +struct Item<'a> { + v: u8, + log: &'a Log, +} + +impl Drop for Item<'_> { + fn drop(&mut self) { + self.log.borrow_mut().push(format!("drop {}", self.v)); + } +} + +/// The crate's own collection, which reads its items only up to the first 0, dropping +/// that one and leaving the rest in the iterator, which drops as `from_iter` returns. +struct Bag<'a> { + items: Vec>, +} + +impl<'a> FromIterator> for Bag<'a> { + fn from_iter>>(iter: I) -> Self { + let mut iter = iter.into_iter(); + let mut items = Vec::new(); + for item in iter.by_ref() { + if item.v == 0 { + break; + } + items.push(item); + } + if let Some(item) = items.first() { + item.log.borrow_mut().push(format!("bag of {}", items.len())); + } + Bag { items } + } +} + +impl<'a> IntoIterator for Bag<'a> { + type Item = Item<'a>; + type IntoIter = std::vec::IntoIter>; + + fn into_iter(self) -> Self::IntoIter { + self.items.into_iter() + } +} + +impl<'a, 'b> IntoIterator for &'b Bag<'a> { + type Item = &'b Item<'a>; + type IntoIter = std::slice::Iter<'b, Item<'a>>; + + fn into_iter(self) -> Self::IntoIter { + self.items.iter() + } +} + +/// The crate's own collection of any type, which keeps its items in reverse and counts +/// them, so a `collect` that skipped it would differ. +struct Stack { + items: Vec, + count: usize, +} + +impl FromIterator for Stack { + fn from_iter>(iter: I) -> Self { + let mut items: Vec = iter.into_iter().collect(); + items.reverse(); + let count = items.len(); + Stack { items, count } + } +} + +/// The crate's own collection of the first three reads of its iterator, which reads on past +/// a `None`, as nothing stops it from doing. +struct Tries(Vec>); + +impl FromIterator for Tries { + fn from_iter>(iter: I) -> Self { + let mut iter = iter.into_iter(); + Tries((0..3).map(|_| iter.next()).collect()) + } +} + +/// What counts down from `n`, by the crate's own iterator. +struct Count<'a> { + n: u8, + log: &'a Log, +} + +impl<'a> IntoIterator for Count<'a> { + type Item = u8; + type IntoIter = Down<'a>; + + fn into_iter(self) -> Down<'a> { + self.log.borrow_mut().push(format!("count {}", self.n)); + Down { + n: self.n, + log: self.log, + } + } +} + +/// The crate's own iterator, which logs each read and its drop. +struct Down<'a> { + n: u8, + log: &'a Log, +} + +impl Iterator for Down<'_> { + type Item = u8; + + fn next(&mut self) -> Option { + self.log.borrow_mut().push(format!("next {}", self.n)); + self.n = self.n.checked_sub(1)?; + Some(self.n) + } +} + +impl Drop for Down<'_> { + fn drop(&mut self) { + self.log.borrow_mut().push(format!("down dropped at {}", self.n)); + } +} + +/// What `values` reads, each at most `limit`, and the log. +fn write<'a>(out: &mut Vec, log: &Log, values: impl IntoIterator>) { + let values: Vec = values.into_iter().map(|item| item.v).collect(); + put(out, &format!("{values:?}")); + put(out, &log.borrow_mut().drain(..).collect::>().join(", ")); +} + +/// What makes an `Item` of each byte, logging it, and how far a case reads. +macro_rules! setup { + ($log:ident, $item:ident, $k:ident = $kind:ident >> $shift:literal) => { + let $log = Log::default(); + let $item = |v: u8| { + $log.borrow_mut().push(format!("make {v}")); + Item { v, log: &$log } + }; + let $k = usize::from($kind >> $shift); + }; +} + +/// `collect` into the crate's collections, which read their source lazily up to its first +/// 0, and into a `Result` or an `Option` of one, which stops at its first `Err` or `None`. +pub fn collects(kind: u8, data: &[u8], out: &mut Vec) { + setup!(log, item, k = kind >> 3); + match kind % 8 { + 0 => { + let bag: Bag = data.iter().map(|&v| item(v)).collect(); + write(out, &log, &bag); + } + 1 => { + let bag = data + .iter() + .rev() + .filter(|&&v| v % 3 != 1) + .map(|&v| item(v)) + .collect::(); + write(out, &log, bag.items.iter().take(k)); + } + 2 => { + let items: Vec = data.iter().map(|&v| item(v)).collect(); + let bag: Bag = items.into_iter().skip(k).collect(); + write(out, &log, &bag); + } + 3 => { + let bag: Result = data + .iter() + .map(|&v| match v { + 0xf0.. => Err(v), + _ => Ok(item(v)), + }) + .collect(); + match bag { + Ok(bag) => write(out, &log, &bag), + Err(e) => put(out, &format!("err {e}")), + } + } + 4 => { + let bag: Option = data.iter().map(|&v| (v < 0xf0).then(|| item(v))).collect(); + let len = bag.as_ref().map(|bag| bag.items.len()); + put(out, &format!("{len:?}")); + write(out, &log, bag.iter().flatten()); + } + // The crate's own generic collection. + 5 => { + let stack: Stack = data.iter().map(|&v| u16::from(v) * 3).collect(); + put(out, &format!("{:?} {}", stack.items, stack.count)); + let stack: Stack = data.iter().take(k).map(|&v| item(v)).collect(); + write(out, &log, &stack.items); + } + // Of the crate's own iterator, by value and borrowed. + 6 => { + let n = data.first().map_or(0, |v| v % 9); + let stack: Stack = Down { n, log: &log }.collect(); + put(out, &format!("{:?} {}", stack.items, stack.count)); + let mut down = Down { n, log: &log }; + let stack: Stack = down.by_ref().take(k).collect(); + put(out, &format!("{:?} {} {:?}", stack.items, stack.count, down.next())); + } + // Into a `Result` or an `Option` of one that reads on past an `Err` or a `None`, which + // keeps the last `Err`, dropping the one it replaces. + _ => { + let tries: Result, Item> = data + .iter() + .map(|&v| if v % 3 == 0 { Err(item(v)) } else { Ok(v) }) + .collect(); + match tries { + Ok(Tries(values)) => put(out, &format!("{values:?}")), + Err(e) => put(out, &format!("err {}", e.v)), + } + let tries: Option> = data.iter().map(|&v| (v % 3 != 0).then(|| item(v))).collect(); + let values = tries.map(|Tries(values)| { + values + .iter() + .map(|item| item.as_ref().map(|item| item.v)) + .collect::>() + }); + put(out, &format!("{values:?}")); + } + } + write(out, &log, []); +} + +/// `flat_map` and `flatten` over the crate's collections, by value and by reference, and +/// over one whose iterator is the crate's own, read only so far. +pub fn flattens(kind: u8, data: &[u8], out: &mut Vec) { + setup!(log, item, k = kind >> 3); + match kind % 8 { + // Read up to `k`, then from the back. + 0 => { + let mut it = data + .chunks(3) + .flat_map(|chunk| chunk.iter().map(|&v| item(v)).collect::()); + let front: Vec = it.by_ref().take(k).collect(); + let back = it.next_back().map(|item| item.v); + log.borrow_mut().push(format!("back {back:?}")); + drop(it); + write(out, &log, &front); + } + 1 => { + let bags: Vec = data + .chunks(2) + .map(|chunk| chunk.iter().map(|&v| item(v)).collect()) + .collect(); + write(out, &log, bags.iter().flatten().skip(k)); + let found = bags.into_iter().flatten().find(|item| usize::from(item.v) == k); + write(out, &log, found.as_ref()); + } + 2 => { + let bags: Vec = data + .chunks(2) + .map(|chunk| chunk.iter().map(|&v| item(v)).collect()) + .collect(); + write(out, &log, (0..bags.len()).rev().flat_map(|i| &bags[i]).step_by(k + 1)); + } + // The crate's own iterator, which drops where std's adaptor ends. + 3 => { + let counts: Vec = data + .iter() + .flat_map(|&v| Count { n: v % 5, log: &log }) + .take(k) + .collect(); + put(out, &format!("{counts:?}")); + } + 4 => { + let counts = data.iter().map(|&v| Count { n: v % 4, log: &log }); + let sum = counts.flatten().fold(0u32, |sum, v| sum + u32::from(v)); + put(out, &format!("{sum}")); + } + _ => {} + } + write(out, &log, []); +} + +/// `chain`, `zip`, and `extend` of the crate's collections. +pub fn chains(kind: u8, data: &[u8], out: &mut Vec) { + setup!(log, item, k = kind >> 1); + match kind % 2 { + 0 => { + let bag: Bag = data.iter().take(k).map(|&v| item(v)).collect(); + let other: Bag = data.iter().skip(k).map(|&v| item(v)).collect(); + write(out, &log, bag.items.iter().chain(&other)); + let mut items: Vec = bag.into_iter().chain(other).collect(); + let more: Bag = data.iter().rev().map(|&v| item(v)).collect(); + items.extend(more); + write(out, &log, &items); + } + _ => { + let bag: Bag = data.iter().map(|&v| item(v)).collect(); + let pairs: Vec<(u8, u8)> = data + .iter() + .zip(Count { n: 4, log: &log }) + .map(|(&a, b)| (a, b)) + .collect(); + put(out, &format!("{pairs:?}")); + let zipped: Vec = (0..k).zip(bag).map(|(_, item)| item.v).collect(); + put(out, &format!("{zipped:?}")); + } + } + write(out, &log, []); +} diff --git a/ts/fixtures/lang/collects/src/lib.rs b/ts/fixtures/lang/collects/src/lib.rs new file mode 100644 index 000000000..2ef26d686 --- /dev/null +++ b/ts/fixtures/lang/collects/src/lib.rs @@ -0,0 +1,23 @@ +//! A part of the language the driver translates, exercised against native Rust: what +//! each of its modules says. + +mod collects; +#[path = "../../harness.rs"] +pub mod harness; +#[cfg(target_arch = "wasm32")] +#[path = "../../../wasm.rs"] +mod wasm; +#[cfg(target_arch = "wasm32")] +use harness::run as entry; + +use harness::Case; + +/// Each case's name and what it runs. The first two bytes, big-endian, pick one modulo +/// their count, so a case added at the end moves no other. +fn cases() -> Vec<(&'static str, Case)> { + vec![ + ("collects::collects", collects::collects), + ("collects::flattens", collects::flattens), + ("collects::chains", collects::chains), + ] +} diff --git a/ts/fixtures/lang/collects/ts.toml b/ts/fixtures/lang/collects/ts.toml new file mode 100644 index 000000000..d4f3cf963 --- /dev/null +++ b/ts/fixtures/lang/collects/ts.toml @@ -0,0 +1,2 @@ +package = "lang-collects-fixture" +roots = ["harness::run", "harness::op"] diff --git a/ts/fixtures/task/expected/drops/iters.ts b/ts/fixtures/task/expected/drops/iters.ts index ada1125bb..dfbccff97 100644 --- a/ts/fixtures/task/expected/drops/iters.ts +++ b/ts/fixtures/task/expected/drops/iters.ts @@ -343,7 +343,7 @@ export function collected(log: Log.Log, id: rs.u32): void { return rs.Ok(g2); } return rs.Err(g2); - }), (values: rs.Iter) => rs.iterToVec(values, "next", 8, false, 8), lib_drop$Vec_model_Guard); + }), (values: rs.Iter) => rs.iterToVec(values, "next", 8, false, 8), lib_drop$Vec_model_Guard, rs.drop); const part = results.ok; Log.note(log, rs.fmtFormat(["result ", (f: rs.Formatter) => rs.fmtBool(part, f)])); lib_drop$Result_Vec_model_Guard_model_Guard(results); diff --git a/ts/runtime/rs/iter.ts b/ts/runtime/rs/iter.ts index acc32c383..3cb3e55b0 100644 --- a/ts/runtime/rs/iter.ts +++ b/ts/runtime/rs/iter.ts @@ -1691,11 +1691,12 @@ function toByteVec(it: Iter, take?: Take, trusted = false): ByteVec { } /** - * `collect` of `Result`s: the first error, or every value collected by `into`, which drops - * the iterator. On an error, what it collected drops by `drop`. + * `collect` of `Result`s: the last error `into` read, or every value collected by `into`, + * which drops the iterator. On an error, what it collected drops by `drop`, and an error a + * later one replaced by `dropError`. */ -export function iterCollectResult(it: Iter>, into: (values: Iter) => C, drop?: Drop): Result { - const shunt = new ResultShunt(it); +export function iterCollectResult(it: Iter>, into: (values: Iter) => C, drop?: Drop, dropError?: Drop): Result { + const shunt = new ResultShunt(it, dropError); const values = into(shunt); if (shunt.error === undefined) return Ok(values); const error = Err(shunt.error.value); @@ -4928,16 +4929,25 @@ export function peekableNextIfEq(p: Peekable, expected: U, eq: (a: T, b return peekableNextIf(p, (item: T) => eq(item, expected), none); } -/** What `iterCollectResult` collects from: values until the first error, which it keeps. */ +/** + * What `iterCollectResult` collects from: values until an error, which it keeps. Read + * again, it reads on, as std's does, and a later error replaces it, which drops by `dropError`. + */ class ResultShunt extends Adaptor, U> { error: { value: E } | undefined; + private readonly dropError: Drop | undefined; + + constructor(inner: Iter>, dropError: Drop | undefined) { + super(inner); + this.dropError = dropError; + } /** std's, by `try_for_each`, which folds its iterator. */ next(): U | Done { - if (this.error !== undefined) return DONE; const item = this.inner.folded().next(); if (item === DONE) return DONE; if (item.ok) return item.value; + if (this.error !== undefined) this.dropError?.(this.error.value); this.error = { value: item.error }; return DONE; } @@ -4947,7 +4957,10 @@ class ResultShunt extends Adaptor, U> { } } -/** What `iterCollectOption` collects from: values until the first `None`, which is `itemNone`. */ +/** + * What `iterCollectOption` collects from: values until a `None`, which is `itemNone`. Read + * again, it reads on, as std's does. + */ class OptionShunt extends Adaptor { none = false; private readonly itemNone: None | undefined; @@ -4958,7 +4971,6 @@ class OptionShunt extends Adaptor { } next(): U | Done { - if (this.none) return DONE; const item = this.inner.folded().next(); if (item === DONE) return DONE; if (item !== this.itemNone) return item as U; diff --git a/ts/src/lower/iter.rs b/ts/src/lower/iter.rs index 38349385b..15d260fc4 100644 --- a/ts/src/lower/iter.rs +++ b/ts/src/lower/iter.rs @@ -514,6 +514,21 @@ fn own_collect<'tcx>( Some((vec, Expr::Sym(b.t.instance(instance)))) } +/// The crate's own impl of `tr::name`, a function of std's trait `tr`, for `args`, the type +/// it is for first, as a value: its `FromIterator` or `IntoIterator`, which std's adaptors +/// call. +fn own_impl<'tcx>(b: &mut Body<'_, '_, 'tcx>, tr: &str, name: &str, args: &[Ty<'tcx>], span: Span) -> Option { + let tcx = b.t.tcx; + // Over parameters, only a census's instance, which never runs, would call it. + if args.iter().any(|t| t.has_param() || t.has_aliases()) { + return None; + } + let f = super::collections::trait_fn(tcx, tr, name); + let args = tcx.mk_args_from_iter(args.iter().map(|&t| ty::GenericArg::from(t))); + let instance = Instance::try_resolve(tcx, b.t.typing_env_pub(), f, args).ok()??; + b.t.own(instance.def_id()).then(|| b.fn_value(f, args, span)) +} + /// Whether `ty` holds, by value rather than through a reference, an iterator of the crate with a /// method in `BY_VALUE` of its own, which std's consumers call where they take it. fn folds_own<'tcx>(b: &Body<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { @@ -792,6 +807,10 @@ fn peeled_into_iter<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, value: Expr, None => value, }); } + // The crate's own collection, by its own `IntoIterator`, as the iterator that makes. + if let Some(into) = own_impl(b, "IntoIterator", "into_iter", &[ty], span) { + return into_iter(b, iter_of(b.t, ty)?, into.call(vec![value]), span); + } // What drops each item of one that owns them. let each = |b: &mut Body<'_, '_, 'tcx>, elem: Ty<'tcx>, mut args: Vec| { if owned && b.t.drops(elem) { @@ -1166,6 +1185,12 @@ pub fn call<'tcx>( }; return Some(Expr::rs("iterToOption", [item].into_iter().chain(none).collect())); } + // Into the crate's own collection, its `from_iter` of the iterator, as std's `collect` is. + if name == "collect" + && let Some(from_iter) = own_impl(b, "FromIterator", "from_iter", &[targ(1)?, item, targ(0)?], span) + { + return Some(from_iter.call(vec![first])); + } let recv = into_iter(b, self_ty, first, span)?; // `rs.iter(recv, ...args)`, or `peekable` of a `Peekable`'s own. let method = |name: &str, args: Vec| { @@ -2065,6 +2090,13 @@ fn collect<'tcx>( span: Span, ) -> Option { let tcx = b.t.tcx; + // The crate's own collection's `from_iter` of `iter`, which is the value of `from` but for + // the crate's own iterator, which `rs.iterFrom` wraps. + if own_next(b, from.peel_refs()).is_none() + && let Some(from_iter) = own_impl(b, "FromIterator", "from_iter", &[ty, item, from], span) + { + return Some(from_iter.call(vec![iter])); + } // `()`'s reads every item, each a `()` too, by `for_each`, which folds: from `undefined`, // so the result is typed as `()` is. if ty.is_unit() { @@ -2116,7 +2148,8 @@ fn collect<'tcx>( }); } match std { - // The values, collected as the `Ok` or `Some` type is, until the first `Err` or `None`. + // The values, collected as the `Ok` or `Some` type is, until an `Err` or `None`, the last + // the collection read. std @ (Std::Result | Std::Option) => { let ty::Adt(_, item_args) = item.kind() else { return None; @@ -2148,7 +2181,11 @@ fn collect<'tcx>( let dropper = b.t.dropper(args.type_at(0), span); let collected = vec![iter, Expr::Lambda(vec![param], Box::new(values))]; Some(match std { - Std::Result => Expr::rs("iterCollectResult", tail(collected, vec![dropper])), + // A later error replaces an earlier one, which then drops. + Std::Result => { + let error = b.t.dropper(args.type_at(1), span); + Expr::rs("iterCollectResult", tail(collected, vec![dropper, error])) + } // The items' `None`, and the result's, each `rs.None` where `undefined` is a value. _ => { let nones = [value, args.type_at(0)].map(|t| b.t.none(t)); @@ -2177,10 +2214,12 @@ fn collect<'tcx>( } /// Whether `ty`, collected through a `GenericShunt`, is given it: a tuple, whose `Extend` -/// is, or a `Result` or `Option` of one, which shunts it again. +/// is, the crate's own collection, whose `FromIterator` is, or a `Result` or `Option` of +/// one, which shunts it again. fn sees_shunt<'tcx>(t: &Translator<'_, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Tuple(_) => true, + ty::Adt(adt, _) if t.own(adt.did()) => true, ty::Adt(_, args) if matches!(t.std_of(ty), Some(Std::Result | Std::Option)) => sees_shunt(t, args.type_at(0)), _ => false, } diff --git a/ts/tests/fixtures.rs b/ts/tests/fixtures.rs index b47fc389f..bbc881451 100644 --- a/ts/tests/fixtures.rs +++ b/ts/tests/fixtures.rs @@ -442,6 +442,7 @@ mod lang { chars, chunks, clones, + collects, collections, combinators, constants,