diff --git a/quest/m3/README.md b/quest/m3/README.md index 8cb3e764f..3ff2ce178 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -25,7 +25,8 @@ generic std gap is planned here even when moq never calls it. - [Wakers made from a RawWaker](/quest/m3/ts-raw-waker.md) - `Waker::from_raw` and the rest of the raw waker API translate, each vtable call where std makes it - [Waiting: a slice object for a mutable part of other values](/quest/m3/ts-slice-object.md) - waits on a moq profile showing the `Proxy` view's traps matter, then decides on an `rt.ByteSlice`-like form - [Port the workflow guard to kixelated/quest](/quest/m3/quest-workflow-guard.md) - quest's environment guard parses YAML as this repository's does -- [Debug of std's other iterators](/quest/m3/ts-iter-source-debug.md) - `Debug` of `str`'s searcher iterators, a `BTreeSet`'s set operations, `ExtractIf`, and `repeat`, `repeat_n`, and `once_with` writes what std's does +- [Debug of a str's searches](/quest/m3/ts-iter-source-debug.md) - `Debug` of `str`'s `Split` and its forms, `Matches`, `Lines`, and `SplitWhitespace` writes their searcher's state as std's does +- [A B-tree's extract_if](/quest/m3/ts-btree-extract-if.md) - `BTreeMap::extract_if` and `BTreeSet::extract_if` translate, with their `Debug` - [A vector keeps the capacity its pushes grew as it shrinks](/quest/m3/ts-vec-clear-capacity.md) - every step that drops a pushed `Vec`'s length keeps its capacity, as std guarantees - [A vector's exact capacity as it shrinks](/quest/m3/ts-vec-exact-capacity.md) - a deque made from a `Vec` splits its slices where std's does - [A B-tree's searches call Ord as std's do](/quest/m3/ts-btree-search-order.md) - a B-tree's lookups and inserts call a key's own `Ord` in std's order and number diff --git a/quest/m3/ts-btree-extract-if.md b/quest/m3/ts-btree-extract-if.md new file mode 100644 index 000000000..d4ec21745 --- /dev/null +++ b/quest/m3/ts-btree-extract-if.md @@ -0,0 +1,15 @@ +# [S] A B-tree's extract_if + +## Goal + +[rust2-ts](/ts/README.md) translates `BTreeMap::extract_if` and `BTreeSet::extract_if`, +which it refuses now: each entry in the range its closure returns true for, taken out as it +is read in key order, the rest kept once it drops, and `Debug` of their `ExtractIf`, which +writes the entry it reads next as `peek`. Proven by differential tests against native Rust. + +## Plan + +The runtime's B-tree keeps its keys in linked leaves, which a removal while a `BTreeIter` +reads them may rebalance; the iterator has to survive that as std's cursor does. A map's +closure takes `&mut V`, lent as a place where JS copies the value, as `retain`'s is. No +consumer calls them yet; they are planned here as part of std. diff --git a/quest/m3/ts-iter-source-debug.md b/quest/m3/ts-iter-source-debug.md index 781a6bcc0..0657f8db0 100644 --- a/quest/m3/ts-iter-source-debug.md +++ b/quest/m3/ts-iter-source-debug.md @@ -1,29 +1,22 @@ -# [M] Debug of std's other iterators +# [M] Debug of a str's searches ## Goal -[rust2-ts](/ts/README.md) translates `Debug` of the std iterators that still have no -mapping, writing what std's does instead of being refused: `str`'s iterators other than -`Chars`, `Bytes`, `CharIndices`, and the escapes (`Split` and its forms, `Lines`, -`SplitWhitespace`, `Matches`, `MatchIndices`), a `BTreeSet`'s set operations, and each -`ExtractIf`. `iter::repeat`, `repeat_n`, and `once_with`, which are not translated at all -yet, translate with their `Debug`. Proven by differential tests against native Rust. +[rust2-ts](/ts/README.md) translates `Debug` of `str`'s searching iterators, which it +refuses now: `Split` and its forms, `Matches`, `MatchIndices`, `Lines`, and +`SplitWhitespace`, writing what std's does fresh, `{:#?}`, and after reads from either end. +Proven by differential tests against native Rust. ## Plan -The sources, `Option`'s, `Result`'s, and an array's iterators, a slice's parts, and a hash -set's operations landed on `iter_debug` in `src/lower/fmt.rs`; extend it the same way. +std writes each searcher's private state, which the runtime does not keep in std's shape: +a `CharSearcher`'s `finger` and `finger_back` in UTF-8 bytes, a `StrSearcher`'s +`TwoWaySearcher` (`crit_pos`, `period`, `byteset`, `position`, `memory`) or an empty +needle's flags, and a closure's or a char set's `CharIndices`. The runtime searches in +UTF-16 code units by a `Pattern`, so it would track std's state beside its own, replay +std's search when written, or search as std does; measure the cost to plain searches +before choosing. `Lines` and `SplitWhitespace` wrap a `SplitInclusive` and a `Split`, so +they follow from those. -What is left writes private state the runtime does not keep in std's shape: - -- `str`'s searcher iterators write their searcher's fields: a `CharSearcher`'s - `finger` and `finger_back` in UTF-8 bytes, a `StrSearcher`'s `TwoWaySearcher` state - (`crit_pos`, `period`, `byteset`, `memory`), and an empty needle's flags. The runtime - searches in UTF-16 code units by a `Pattern`, so it would track std's state beside its - own, or search as std does. -- A `BTreeSet`'s `Difference` and `Intersection` write which strategy std picked - (`Stitch`, `Search`, `Iterate`, `Answer`) and its iterators, `Search` the whole other - set; `Union` and `SymmetricDifference` their `MergeIterInner`'s peeked item. The runtime - already picks std's strategy, so its state may map over. -- `Vec`'s, `LinkedList`'s, and a B-tree's `ExtractIf` write the item they peek at; a hash - map's and set's write `ExtractIf { .. }` once their `extract_if` translates. +`SplitAsciiWhitespace` has no mapping at all yet, and std writes it as a slice's `Split` of +the bytes left. diff --git a/quest/m3/ts-vec-rest.md b/quest/m3/ts-vec-rest.md index 27549d874..737574d90 100644 --- a/quest/m3/ts-vec-rest.md +++ b/quest/m3/ts-vec-rest.md @@ -18,9 +18,9 @@ elements through raw pointers, so each refuses with its span. - `VecDeque::rotate_left`, `rotate_right`, `swap`, `make_contiguous`, `binary_search`, `binary_search_by`, `binary_search_by_key`, and `partition_point`, each placing its items where std's does, which `as_slices` shows. -- `Vec::splice`, `extract_if` of elements JS copies, `into_flattened`, `leak`, and - `spare_capacity_mut`; the last two hand out memory past the length, which may stay - refused. +- `Vec::splice`, `extract_if` with its `Debug` (`retained`, `remainder`, and + `skipped_tail`), `into_flattened`, `leak`, and `spare_capacity_mut`; the last two hand + out memory past the length, which may stay refused. A vector's capacity follows only std's guarantees, at least its length and what `with_capacity` and `reserve` ask for, and doubles as it grows (decided with the diff --git a/ts/README.md b/ts/README.md index 995c1b32d..44397174f 100644 --- a/ts/README.md +++ b/ts/README.md @@ -296,12 +296,17 @@ its length, as std's do. `Debug` of std's iterator adaptors, `Map` through `Flat `DecodeUtf16`, and a `str`'s escapes, writes their fields as std's does, each iterator it wraps by its own `Debug`, no closure, and the state each keeps, such as what a `Peekable` peeked, what a `Skip` has left to skip, and the countdown std's `StepBy` of a small unsigned range keeps -in its end. So does `Debug` of std's sources, `Once`, `FromFn`, `RepeatWith`, and -`Successors`, an `Option`'s, a `Result`'s, and an array's iterators, a `CharIndices`, a -`String`'s `Drain`, and a slice's `Windows`, chunks, and splits, each writing what is left of -its slice as std's does, emptied where std's `nth` past the end empties a `Windows`; a hash -set's operations write the list a clone yields. A slice's `chunks_mut` and its forms are -refused, as std writes their slice's address. `Debug` of `Bound`, `Ordering`, `Reverse`, `AssertUnwindSafe`, and `ControlFlow` is +in its end. So does `Debug` of std's sources, `Once`, `OnceWith`, `FromFn`, `Repeat`, +`RepeatN`, `RepeatWith`, and `Successors`, an `Option`'s, a `Result`'s, and an array's +iterators, a `CharIndices`, a `String`'s `Drain`, and a slice's `Windows`, chunks, and +splits, each writing what is left of its slice as std's does, emptied where std's `nth` past +the end empties a `Windows`; a hash set's operations write the list a clone yields, and a +`BTreeSet`'s the way std picked to make each, by the iterators it reads, the set it looks +keys up in, and the key it peeked or holds back. A list's `ExtractIf` writes the item it +reads next, and a hash map's and set's nothing. A slice's `chunks_mut` and its forms are +refused, as std writes their slice's address, and so are a `str`'s searches, `Split` and +its forms, `Matches`, `MatchIndices`, `Lines`, and `SplitWhitespace`, as std writes its +searcher's state in UTF-8 bytes. `Debug` of `Bound`, `Ordering`, `Reverse`, `AssertUnwindSafe`, and `ControlFlow` is their derived one, whichever way each is held, and a guard of a cell or a lock, mapped or not, writes what it lends by its own `Debug` and `Display`. `Debug` of a `Cell`, a `RefCell`, a `Mutex`, and an `RwLock` writes what each holds, or `` and diff --git a/ts/fixtures/lang/clones/expected/clones.Counted.ts b/ts/fixtures/lang/clones/expected/clones.Counted.ts new file mode 100644 index 000000000..0138cf40f --- /dev/null +++ b/ts/fixtures/lang/clones/expected/clones.Counted.ts @@ -0,0 +1,18 @@ +// Generated by rust2-ts. Do not edit. + +import * as rt from "./rt.ts"; + +/** Logs its id as it is cloned, as `Logged` does, but drops as nothing. */ +export interface Counted { + id: rt.u8; + log: rt.RefCell; +} + +export function clone$Clone(self: Counted): Counted { + const _5: rt.RefCell = rt.refCellBorrowMut(self.log); + rt.byteVecPush(_5.value, 128 | self.id); + rt.refMutRelease(_5); + return { id: rt.u8WrappingAdd(self.id, 1), log: self.log }; +} + +//# sourceMappingURL=clones.Counted.ts.map diff --git a/ts/fixtures/lang/clones/expected/clones.ts b/ts/fixtures/lang/clones/expected/clones.ts index 6b01e3656..9f248271c 100644 --- a/ts/fixtures/lang/clones/expected/clones.ts +++ b/ts/fixtures/lang/clones/expected/clones.ts @@ -3,6 +3,7 @@ import * as rt from "./rt.ts"; import { drop$Vec_clones_Logged, drop$array1_clones_Logged, drop$array2_clones_Kept, drop$array2_clones_Logged, drop$clones_Slot, drop$tuple2_Option_Vec_clones_Logged_Option_Vec_clones_Logged, drop$tuple2_Vec_array2_clones_Logged_array2_array2_clones_Logged, drop$tuple2_Vec_clones_Logged_Vec_Vec_clones_Logged, drop$tuple2_Vec_clones_Logged_Vec_clones_Logged, drop$tuple2_array2_array2_clones_Logged_array2_array2_clones_Logged, drop$tuple2_clones_Logged_String, drop$tuple2_tuple3_array2_clones_Logged_String_clones_Logged_clones_Pair, drop$tuple3_Option_array2_clones_Logged_Option_array2_clones_Logged_Option_array2_clones_Logged, drop$tuple3_Vec_Option_clones_Logged_Vec_Option_clones_Logged_Vec_tuple2_clones_Logged_String, drop$tuple3_Vec_Vec_clones_Logged_Vec_Vec_clones_Logged_Vec_Vec_clones_Logged, drop$tuple3_Vec_array2_clones_Logged_Vec_array2_clones_Logged_array2_clones_Logged, drop$tuple3_Vec_clones_Logged_Vec_clones_Logged_Vec_clones_Logged, drop$tuple3_array0_clones_Logged_array0_clones_Logged_array3_clones_Logged, drop$tuple3_array2_clones_Logged_String_clones_Logged, drop$tuple3_array3_clones_Logged_array3_clones_Logged_array3_clones_Logged, drop$tuple4_boxed_Box_slice_clones_Logged_boxed_Box_slice_clones_Logged_boxed_Box_slice_array1_clones_Logged_boxed_Box_slice_array1_clones_Logged, drop$tuple7_Vec_clones_Kept_Vec_clones_Kept_array1_array2_clones_Kept_Option_clones_Kept_array2_clones_Slot_collections_LinkedList_clones_Kept_collections_LinkedList_clones_Kept } from "./lib.ts"; import * as Countdown from "./clones.Countdown.ts"; +import * as Counted from "./clones.Counted.ts"; import * as Fussy from "./clones.Fussy.ts"; import * as Kept from "./clones.Kept.ts"; import * as Logged from "./clones.Logged.ts"; @@ -10,7 +11,7 @@ import * as Pair from "./clones.Pair.ts"; import * as Plan from "./clones.Plan.ts"; import * as Slot from "./clones.Slot.ts"; import { then$1uqvqbl } from "./core/bool.ts"; -import { unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$0y3liwu as option_map$0y3liwu, mapOr$1yabfom as option_mapOr$1yabfom, mapOr$1surhce as option_mapOr$1surhce, mapOr$02k4ito as option_mapOr$02k4ito, clone$0bhdqd8 as option_clone$0bhdqd8, clone$1jx0028 as option_clone$1jx0028 } from "./core/option.ts"; +import { isSomeAnd$09tpccf, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$0y3liwu as option_map$0y3liwu, mapOr$0w6m9d0 as option_mapOr$0w6m9d0, mapOr$0bq8trh as option_mapOr$0bq8trh, mapOr$1yabfom as option_mapOr$1yabfom, mapOr$1surhce as option_mapOr$1surhce, mapOr$02k4ito as option_mapOr$02k4ito, clone$0bhdqd8 as option_clone$0bhdqd8, clone$1jx0028 as option_clone$1jx0028 } from "./core/option.ts"; /** Puts what was logged since the last flush, after a marker. */ export function flush(log: rt.RefCell, out: rt.ByteVec): void { @@ -8245,4 +8246,282 @@ export function repeated$clones_Logged(x: Logged.Logged, n: rt.usize): Logged.Lo return rt.vecFromElem(x, n, Logged.clone$Clone, rt.drop); } +/** + * `iter::repeat`, `repeat_n`, and `once_with` of values that clone and drop themselves: + * each item a clone of the element, but `repeat_n`'s last, which is the element, read + * from either end, skipped, counted, and dropped part read, a `Take` of a `Repeat` read + * from the back as from the front; `once_with`'s closure called as it is first read, and + * dropped uncalled with it. + */ +export function sources(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void { + let _132!: rt.usize; + let item!: Logged.Logged | undefined; + const _11: (a0: Logged.Logged | undefined) => rt.u8 = (x2: Logged.Logged | undefined): rt.u8 => { + return option_mapOr$0bq8trh(x2, 238, (x3: Logged.Logged): rt.u8 => { + const _02: rt.u8 = Logged.id(x3); + x3[Symbol.dispose](); + return _02; + }); + }; + const _12: (a0: [rt.usize, rt.usize | undefined]) => Uint8Array = (hint: [rt.usize, rt.usize | undefined]): Uint8Array => { + return Uint8Array.of(rt.min(hint[0], 253) & 0xff, option_mapOr$02k4ito(hint[1], 254, (n2: rt.usize): rt.u8 => { + return n2 & 0xff; + })); + }; + const _501: (a0: Logged.Logged) => rt.u8 = (x4: Logged.Logged): rt.u8 => { + return Logged.id(x4); + }; + const log: rt.Arc> = new rt.Arc(new rt.RefCell(new rt.ByteVec())); + const logged: (a0: rt.u8) => Logged.Logged = (id: rt.u8): Logged.Logged => { + return new Logged.Logged(id, rt.arcClone(log)); + }; + const at: (a0: rt.usize) => rt.u8 = (i2: rt.usize): rt.u8 => { + return option_unwrapOr$0r2bmpr(rt.byteSliceGet(data, i2), rt.u8WrappingMul(i2 & 0xff, 48)) & 126; + }; + const n: (a0: rt.usize) => rt.usize = (i3: rt.usize): rt.usize => { + return rt.u8Rem(option_unwrapOr$0r2bmpr(rt.byteSliceGet(data, i3), i3 & 0xff), 5) as rt.usize; + }; + const _13: rt.u8 = rt.u8Rem(kind, 6); + if (_13 === 0) { + const part27 = at(0); + const it: rt.Iter = rt.iterRepeat(logged(part27), Logged.clone$Clone, rt.drop); + const part28 = it.sizeHint(); + rt.iterExtendBytes(out, rt.iterSlice(_12(part28)), undefined, true); + const part29 = rt.iterToOption(it.next()); + rt.byteVecPush(out, _11(part29)); + const part30 = rt.iterToOption(it.nextBack()); + rt.byteVecPush(out, _11(part30)); + const _46: rt.usize = n(1); + const part31 = rt.iterNth(it, _46, rt.drop); + rt.byteVecPush(out, _11(part31)); + const _55: rt.usize = n(2); + const part32 = rt.iterNthBack(it, _55, rt.drop); + rt.byteVecPush(out, _11(part32)); + flush(log.value, out); + const clone: rt.Iter = it.clone(); + flush(log.value, out); + rt.drop(it); + flush(log.value, out); + rt.iterExtendBytes(out, rt.byteVecIntoIter(rt.iterToByteVec(rt.iterMap(rt.iterRev(rt.iterTake(clone.clone(), n(3), rt.drop)), (x11: Logged.Logged): rt.u8 => { + const _024: rt.u8 = Logged.id(x11); + x11[Symbol.dispose](); + return _024; + }), "fold", true)), undefined, true); + flush(log.value, out); + const _85: rt.usize = n(4); + const taken2: rt.Iter = rt.iterTake(clone, _85, rt.drop); + const part33 = rt.iterToOption(taken2.nextBack()); + rt.byteVecPush(out, _11(part33)); + const part34 = rt.iterNthBack(taken2, 1, rt.drop); + rt.byteVecPush(out, _11(part34)); + rt.byteVecPush(out, taken2.len() & 0xff); + const part35 = taken2.sizeHint(); + rt.iterExtendBytes(out, rt.iterSlice(_12(part35)), undefined, true); + flush(log.value, out); + rt.byteVecPush(out, rt.iterRfold(taken2, 0, (acc: rt.u8, x12: Logged.Logged): rt.u8 => { + const _025: rt.u8 = rt.u8WrappingAdd(acc, Logged.id(x12)); + x12[Symbol.dispose](); + return _025; + }, true)); + flush(log.value, out); + } else if (_13 === 1) { + const part24 = at(0); + const it2: rt.Iter = rt.iterRepeatN(logged(part24), n(1), Logged.clone$Clone, rt.drop); + let iterStart: rt.usize = 2; + const iterEnd: rt.usize = 8; + while ((_132 = iterStart++) < iterEnd) { + const i: rt.usize = _132; + const _137: rt.u8 = rt.u8Rem(option_unwrapOr$0r2bmpr(rt.byteSliceGet(data, i), 0), 4); + if (_137 === 0) { + item = rt.iterToOption(it2.next()); + } else if (_137 === 1) { + item = rt.iterToOption(it2.nextBack()); + } else if (_137 === 2) { + const _145: rt.usize = rt.usizeRem(n(rt.usizeAdd(i, 8)), 3); + item = rt.iterNth(it2, _145, rt.drop); + } else { + const _153: rt.usize = rt.usizeRem(n(rt.usizeAdd(i, 8)), 3); + item = rt.iterNthBack(it2, _153, rt.drop); + } + rt.byteVecPush(out, _11(item)); + rt.byteVecPush(out, it2.len() & 0xff); + flush(log.value, out); + if (i === 4) { + const clone2: rt.Iter = it2.clone(); + flush(log.value, out); + rt.iterExtendBytes(out, rt.iterMap(clone2, (x10: Logged.Logged): rt.u8 => { + const _023: rt.u8 = Logged.id(x10); + x10[Symbol.dispose](); + return _023; + }), "fold", true); + flush(log.value, out); + } + } + rt.drop(it2); + flush(log.value, out); + } else if (_13 === 2) { + const part13 = at(0); + rt.byteVecPush(out, rt.ownedCount(rt.iterRepeatN(logged(part13), n(1), Logged.clone$Clone, rt.drop), rt.drop) & 0xff); + flush(log.value, out); + const part14 = at(1); + const part15 = rt.ownedLast(rt.iterRepeatN(logged(part14), n(2), Logged.clone$Clone, rt.drop), rt.drop); + rt.byteVecPush(out, _11(part15)); + flush(log.value, out); + const part16 = at(2); + const all: Logged.Logged[] = rt.iterToArray(rt.iterRepeatN(logged(part16), n(3), Logged.clone$Clone, rt.drop), "fold", 8, true); + flush(log.value, out); + rt.iterExtendBytes(out, rt.iterMap(rt.iterSlice(all), Logged.id), undefined, true); + rt.dropAll(all); + flush(log.value, out); + rt.byteVecPush(out, rt.ownedCount(rt.iterRepeatN(at(3), n(4))) & 0xff); + rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.ownedLast(rt.iterRepeatN(at(4), n(5))), 238)); + const part17 = at(5); + rt.iterExtendBytes(out, rt.byteVecIntoIter(rt.iterToByteVec(rt.iterMap(rt.iterRev(rt.iterTake(rt.iterRepeatN(logged(part17), n(6), Logged.clone$Clone, rt.drop), n(7), rt.drop)), (x9: Logged.Logged): rt.u8 => { + const _019: rt.u8 = Logged.id(x9); + x9[Symbol.dispose](); + return _019; + }), "fold", true)), undefined, true); + flush(log.value, out); + const counted: (a0: rt.u8) => Counted.Counted = (id2: rt.u8): Counted.Counted => { + return { id: id2, log: log.value }; + }; + const part18 = at(7); + const _289: rt.Iter = rt.iterRepeatN(counted(part18), n(8), Counted.clone$Clone); + rt.iterEmpty(); + rt.byteVecPush(out, rt.ownedCount(rt.iterChain(_289, rt.iterEmpty() as rt.Iter)) & 0xff); + flush(log.value, out); + rt.iterEmpty(); + const part19 = at(9); + const _308: rt.Iter = rt.iterRepeatN(counted(part19), n(10), Counted.clone$Clone); + rt.byteVecPush(out, option_mapOr$0w6m9d0(rt.ownedLast(rt.iterChain(rt.iterEmpty() as rt.Iter, _308)), 238, (c2: Counted.Counted): rt.u8 => { + return c2.id; + })); + flush(log.value, out); + rt.byteVecPush(out, rt.ownedCount(rt.iterFlatten(rt.iterOnceWith((): rt.Iter => { + return rt.iterRepeatN({ id: 17, log: log.value }, 3, Counted.clone$Clone); + }), undefined, true)) & 0xff); + flush(log.value, out); + const part20 = at(11); + rt.byteVecPush(out, rt.ownedCount(rt.iterFuse(rt.iterRepeatN(logged(part20), n(12), Logged.clone$Clone, rt.drop), true), rt.drop) & 0xff); + flush(log.value, out); + const part21 = at(6); + const zero: rt.Iter = rt.iterRepeatN(logged(part21), 0, Logged.clone$Clone, rt.drop); + flush(log.value, out); + const part22 = rt.iterToOption(zero.next()); + rt.byteVecPush(out, _11(part22)); + const part23 = zero.sizeHint(); + rt.iterExtendBytes(out, rt.iterSlice(_12(part23)), undefined, true); + rt.drop(zero); + } else if (_13 === 3) { + if (!isSomeAnd$09tpccf(rt.byteSliceFirst(data), (b2: rt.u8): boolean => { + return rt.u8Rem(b2, 2) === 0; + })) { + const part12 = at(1); + rt.byteVecPush(out, option_mapOr$0bq8trh(rt.ownedLast(rt.iterRepeat(logged(part12), Logged.clone$Clone, rt.drop), rt.drop), 238, (x8: Logged.Logged): rt.u8 => { + const _018: rt.u8 = Logged.id(x8); + x8[Symbol.dispose](); + return _018; + })); + } else { + rt.byteVecPush(out, rt.ownedCount(rt.iterRepeat(at(1))) & 0xff); + } + } else if (_13 === 4) { + const part5 = at(0); + const a: Logged.Logged = logged(part5); + const make2 = (captured: Logged.Logged): () => rt.u8 => { + return rt.closure(rt.cloning((): rt.u8 => { + const _013: rt.u8 = Logged.id(captured) ^ 85; + captured[Symbol.dispose](); + return _013; + }, () => make2(Logged.clone$Clone(captured))), (): void => { + captured[Symbol.dispose](); + }); + }; + const it6: rt.Iter = rt.iterOnceWith(make2(a)); + const part6 = it6.sizeHint(); + rt.iterExtendBytes(out, rt.iterSlice(_12(part6)), undefined, true); + const clone3: rt.Iter = it6.clone({ f: rt.closureClone }); + flush(log.value, out); + rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(it6.nextBack()), 238)); + flush(log.value, out); + rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(it6.next()), 238)); + rt.byteVecPush(out, it6.len() & 0xff); + rt.drop(it6); + flush(log.value, out); + rt.iterExtendBytes(out, clone3, "fold", true); + flush(log.value, out); + const part7 = at(1); + const captured2 = logged(part7); + const it7: rt.Iter = rt.iterOnceWith(rt.closure((): Logged.Logged => { + return captured2; + }, (): void => { + captured2[Symbol.dispose](); + })); + flush(log.value, out); + const part8 = rt.iterToOption(it7.next()); + rt.byteVecPush(out, _11(part8)); + flush(log.value, out); + const part9 = at(2); + const captured3 = logged(part9); + const it8: rt.Iter = rt.iterOnceWith(rt.closure((): rt.u8 => { + const _015: rt.u8 = Logged.id(captured3); + captured3[Symbol.dispose](); + return _015; + }, (): void => { + captured3[Symbol.dispose](); + })); + flush(log.value, out); + rt.drop(it8); + flush(log.value, out); + const part10 = at(3); + const captured4 = logged(part10); + const f: () => rt.u8 = rt.closure((): rt.u8 => { + return Logged.id(captured4) ^ 51; + }, (): void => { + captured4[Symbol.dispose](); + }); + rt.byteVecPush(out, f()); + const it9: rt.Iter = rt.iterOnceWith(rt.once(f)); + const part11 = it9.sizeHint(); + rt.iterExtendBytes(out, rt.iterSlice(_12(part11)), undefined, true); + flush(log.value, out); + rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(it9.next()), 238)); + flush(log.value, out); + rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(it9.next()), 238)); + rt.drop(it9); + rt.drop(it7); + } else { + const part = at(0); + rt.iterExtendBytes(out, rt.iterMap(rt.iterTake(rt.iterRepeat(logged(part), Logged.clone$Clone, rt.drop), n(1), rt.drop), (x5: Logged.Logged): rt.u8 => { + const _09: rt.u8 = Logged.id(x5) ^ 1; + x5[Symbol.dispose](); + return _09; + }), "fold", true); + flush(log.value, out); + const part2 = at(1); + for (const _539 of rt.iterToArray(rt.iterMap(rt.iterZip(rt.iterRepeatN(logged(part2), n(2), Logged.clone$Clone, rt.drop), rt.iterRepeat(at(3)), "len", rt.drop), (_2: [Logged.Logged, rt.u8]): [rt.u8, rt.u8] => { + const x6: Logged.Logged = _2[0]; + const y2: rt.u8 = _2[1]; + const _010: [rt.u8, rt.u8] = [_501(x6), y2]; + x6[Symbol.dispose](); + return _010; + }), "fold", 2, true)) { + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_539[0], _539[1])), undefined, true); + } + flush(log.value, out); + const part4 = at(4); + rt.iterExtendBytes(out, rt.byteVecIntoIter(rt.iterToByteVec(rt.iterMap(rt.iterSkip(rt.iterRepeatN(logged(part4), n(5), Logged.clone$Clone, rt.drop), n(6), rt.drop), (x7: Logged.Logged): rt.u8 => { + const _011: rt.u8 = Logged.id(x7); + x7[Symbol.dispose](); + return _011; + }), "next")), undefined, true); + flush(log.value, out); + rt.iterExtendBytes(out, rt.byteVecIntoIter(rt.iterToByteVec(rt.iterRev(rt.iterChain(rt.iterOnceWith((): rt.u8 => { + return at(7); + }), rt.iterRepeatN(at(8), n(9)))), undefined, true)), undefined, true); + } + flush(log.value, out); + log[Symbol.dispose](); +} + //# sourceMappingURL=clones.ts.map diff --git a/ts/fixtures/lang/clones/expected/core/option.ts b/ts/fixtures/lang/clones/expected/core/option.ts index a7a2bcf20..0de06da97 100644 --- a/ts/fixtures/lang/clones/expected/core/option.ts +++ b/ts/fixtures/lang/clones/expected/core/option.ts @@ -1,8 +1,16 @@ // Generated by rust2-ts. Do not edit. import * as rt from "../rt.ts"; +import type * as Counted from "../clones.Counted.ts"; import * as Logged from "../clones.Logged.ts"; +export function isSomeAnd$09tpccf(self: rt.u8 | undefined, f: (a0: rt.u8) => boolean): boolean { + if (self === undefined) { + return false; + } + return f(self); +} + export function unwrapOr$0r2bmpr(self: rt.u8 | undefined, default_: rt.u8): rt.u8 { if (self === undefined) { return default_; @@ -17,6 +25,20 @@ export function map$0y3liwu(self: rt.u8 | undefined, f: (a0: rt.u8) => Logged.Lo return f(self); } +export function mapOr$0w6m9d0(self: Counted.Counted | undefined, default_: rt.u8, f: (a0: Counted.Counted) => rt.u8): rt.u8 { + if (self === undefined) { + return default_; + } + return f(self); +} + +export function mapOr$0bq8trh(self: Logged.Logged | undefined, default_: rt.u8, f: (a0: Logged.Logged) => rt.u8): rt.u8 { + if (self === undefined) { + return default_; + } + return f(self); +} + export function mapOr$1yabfom(self: Logged.Logged | undefined, default_: rt.u8, _: (a0: Logged.Logged) => rt.u8): rt.u8 { if (self === undefined) { return default_; diff --git a/ts/fixtures/lang/clones/expected/lib.ts b/ts/fixtures/lang/clones/expected/lib.ts index b842b1cd2..c66d049e0 100644 --- a/ts/fixtures/lang/clones/expected/lib.ts +++ b/ts/fixtures/lang/clones/expected/lib.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rt from "./rt.ts"; -import { iters, arrays, cloneFroms, repeats } from "./clones.ts"; +import { iters, arrays, cloneFroms, repeats, sources } from "./clones.ts"; import type * as Kept from "./clones.Kept.ts"; import type * as Logged from "./clones.Logged.ts"; import type * as Pair from "./clones.Pair.ts"; @@ -130,7 +130,7 @@ export function drop$tuple7_Vec_clones_Kept_Vec_clones_Kept_array1_array2_clones * 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 [["clones::iters", iters as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["clones::arrays", arrays as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["clones::clone_froms", cloneFroms as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["clones::repeats", repeats as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]]; + return [["clones::iters", iters as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["clones::arrays", arrays as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["clones::clone_froms", cloneFroms as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["clones::repeats", repeats as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["clones::sources", sources as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]]; } //# sourceMappingURL=lib.ts.map diff --git a/ts/fixtures/lang/clones/src/clones.rs b/ts/fixtures/lang/clones/src/clones.rs index dd0ab2db6..fabcea9e1 100644 --- a/ts/fixtures/lang/clones/src/clones.rs +++ b/ts/fixtures/lang/clones/src/clones.rs @@ -981,3 +981,194 @@ pub fn repeats(kind: u8, data: &[u8], out: &mut Vec) { fn repeated(x: T, n: usize) -> Vec { vec![x; n] } + +/// Logs its id as it is cloned, as `Logged` does, but drops as nothing. +struct Counted<'a> { + id: u8, + log: &'a RefCell>, +} + +impl Clone for Counted<'_> { + fn clone(&self) -> Self { + self.log.borrow_mut().push(0x80 | self.id); + Self { + id: self.id.wrapping_add(1), + log: self.log, + } + } +} + +/// `iter::repeat`, `repeat_n`, and `once_with` of values that clone and drop themselves: +/// each item a clone of the element, but `repeat_n`'s last, which is the element, read +/// from either end, skipped, counted, and dropped part read, a `Take` of a `Repeat` read +/// from the back as from the front; `once_with`'s closure called as it is first read, and +/// dropped uncalled with it. +pub fn sources(kind: u8, data: &[u8], out: &mut Vec) { + let log = Rc::new(RefCell::new(Vec::new())); + let logged = |id: u8| Logged { id, log: log.clone() }; + let at = |i: usize| data.get(i).copied().unwrap_or((i as u8).wrapping_mul(0x30)) & 0x7e; + let n = |i: usize| usize::from(data.get(i).copied().unwrap_or(i as u8) % 5); + let id = |x: Option| x.map_or(0xee, |x| x.id()); + let hint = |hint: (usize, Option)| [hint.0.min(0xfd) as u8, hint.1.map_or(0xfe, |n| n as u8)]; + match kind % 6 { + 0 => { + let mut it = std::iter::repeat(logged(at(0))); + out.extend(hint(it.size_hint())); + out.push(id(it.next())); + out.push(id(it.next_back())); + out.push(id(it.nth(n(1)))); + out.push(id(it.nth_back(n(2)))); + flush(&log, out); + let clone = it.clone(); + flush(&log, out); + drop(it); + flush(&log, out); + let taken: Vec = clone.clone().take(n(3)).rev().map(|x| x.id()).collect(); + out.extend(taken); + flush(&log, out); + let mut taken = clone.take(n(4)); + out.push(id(taken.next_back())); + out.push(id(taken.nth_back(1))); + out.push(taken.len() as u8); + out.extend(hint(taken.size_hint())); + flush(&log, out); + let sum = taken.rfold(0u8, |acc, x| acc.wrapping_add(x.id())); + out.push(sum); + flush(&log, out); + } + 1 => { + let mut it = std::iter::repeat_n(logged(at(0)), n(1)); + for i in 2..8 { + let item = match data.get(i).copied().unwrap_or(0) % 4 { + 0 => it.next(), + 1 => it.next_back(), + 2 => it.nth(n(i + 8) % 3), + _ => it.nth_back(n(i + 8) % 3), + }; + out.push(id(item)); + out.push(it.len() as u8); + flush(&log, out); + if i == 4 { + let clone = it.clone(); + flush(&log, out); + out.extend(clone.map(|x| x.id())); + flush(&log, out); + } + } + drop(it); + flush(&log, out); + } + 2 => { + // Its own `count` and `last`, which clone nothing. + out.push(std::iter::repeat_n(logged(at(0)), n(1)).count() as u8); + flush(&log, out); + out.push(id(std::iter::repeat_n(logged(at(1)), n(2)).last())); + flush(&log, out); + let all: Vec = std::iter::repeat_n(logged(at(2)), n(3)).collect(); + flush(&log, out); + out.extend(all.iter().map(Logged::id)); + drop(all); + flush(&log, out); + out.push(std::iter::repeat_n(at(3), n(4)).count() as u8); + out.push(std::iter::repeat_n(at(4), n(5)).last().unwrap_or(0xee)); + let taken: Vec = std::iter::repeat_n(logged(at(5)), n(6)) + .take(n(7)) + .rev() + .map(|x| x.id()) + .collect(); + out.extend(taken); + flush(&log, out); + // Through an adaptor, which reaches its own `count` and `last` even of items that + // never drop. + let counted = |id: u8| Counted { id, log: &log }; + let it = std::iter::repeat_n(counted(at(7)), n(8)).chain(std::iter::empty()); + out.push(it.count() as u8); + flush(&log, out); + let it = std::iter::empty().chain(std::iter::repeat_n(counted(at(9)), n(10))); + out.push(it.last().map_or(0xee, |c| c.id)); + flush(&log, out); + let make = || std::iter::repeat_n(Counted { id: 0x11, log: &log }, 3); + out.push(std::iter::once_with(make).flatten().count() as u8); + flush(&log, out); + let it = std::iter::repeat_n(logged(at(11)), n(12)).fuse(); + out.push(it.count() as u8); + flush(&log, out); + let mut zero = std::iter::repeat_n(logged(at(6)), 0); + flush(&log, out); + out.push(id(zero.next())); + out.extend(hint(zero.size_hint())); + } + 3 => { + // Infinite, so its `count` and `last` panic. + if data.first().is_some_and(|b| b % 2 == 0) { + out.push(std::iter::repeat(at(1)).count() as u8); + } else { + out.push(std::iter::repeat(logged(at(1))).last().map_or(0xee, |x| x.id())); + } + } + 4 => { + // Closures `FnOnce` calls, one that gives up what it owns, and one never called, + // which drops with its iterator. + let a = logged(at(0)); + let mut it = std::iter::once_with(move || a.id() ^ 0x55); + out.extend(hint(it.size_hint())); + let clone = it.clone(); + flush(&log, out); + out.push(it.next_back().unwrap_or(0xee)); + flush(&log, out); + out.push(it.next().unwrap_or(0xee)); + out.push(it.len() as u8); + drop(it); + flush(&log, out); + out.extend(clone); + flush(&log, out); + let b = logged(at(1)); + let mut it = std::iter::once_with(move || b); + flush(&log, out); + out.push(id(it.next())); + flush(&log, out); + let c = logged(at(2)); + let it = std::iter::once_with(move || c.id()); + flush(&log, out); + drop(it); + flush(&log, out); + // Called before, so `Fn` calls it, and it drops after its one call. + let d = logged(at(3)); + let f = move || d.id() ^ 0x33; + out.push(f()); + let mut it = std::iter::once_with(f); + out.extend(hint(it.size_hint())); + flush(&log, out); + out.push(it.next().unwrap_or(0xee)); + flush(&log, out); + out.push(it.next().unwrap_or(0xee)); + } + _ => { + // Read from the front, and through adaptors. + let id = |x: &Logged| x.id(); + let it = std::iter::repeat(logged(at(0))).take(n(1)).map(|x| x.id() ^ 1); + out.extend(it); + flush(&log, out); + let zipped: Vec<(u8, u8)> = std::iter::repeat_n(logged(at(1)), n(2)) + .zip(std::iter::repeat(at(3))) + .map(|(x, y)| (id(&x), y)) + .collect(); + for (x, y) in zipped { + out.extend([x, y]); + } + flush(&log, out); + let skipped: Vec = std::iter::repeat_n(logged(at(4)), n(5)) + .skip(n(6)) + .map(|x| x.id()) + .collect(); + out.extend(skipped); + flush(&log, out); + let chained: Vec = std::iter::once_with(|| at(7)) + .chain(std::iter::repeat_n(at(8), n(9))) + .rev() + .collect(); + out.extend(chained); + } + } + flush(&log, out); +} diff --git a/ts/fixtures/lang/clones/src/lib.rs b/ts/fixtures/lang/clones/src/lib.rs index 3c379e2e2..57ead5f3a 100644 --- a/ts/fixtures/lang/clones/src/lib.rs +++ b/ts/fixtures/lang/clones/src/lib.rs @@ -20,5 +20,6 @@ fn cases() -> Vec<(&'static str, Case)> { ("clones::arrays", clones::arrays), ("clones::clone_froms", clones::clone_froms), ("clones::repeats", clones::repeats), + ("clones::sources", clones::sources), ] } diff --git a/ts/fixtures/lang/collections/expected/collections.ts b/ts/fixtures/lang/collections/expected/collections.ts index 2f2a13ee9..8f771f53c 100644 --- a/ts/fixtures/lang/collections/expected/collections.ts +++ b/ts/fixtures/lang/collections/expected/collections.ts @@ -5650,4 +5650,147 @@ export function cmpByte$ref_orders(o: rt.Ordering): rt.u8 { return o & 0xff; } +/** + * `extract_if` of hash maps and sets: what its closure takes out, by keys JS compares as + * they are and keys found by their `Hash`, all colliding, with values changed in place as + * each is read, and what stays, each sorted. Read part way, it takes out only what it + * read, and the rest stays. + */ +export function extracts(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void { + let _176!: rt.u8; + const keep: rt.u8 = option_mapOr$1surhce(rt.byteSliceFirst(data), 2, (b: rt.u8): rt.u8 => { + return rt.u8Add(rt.u8Rem(b, 3), 2); + }); + const _6: rt.u8 = rt.u8Rem(kind, 3); + if (_6 === 0) { + const _9: rt.Iter<[rt.u8, rt.u16]> = rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_212: rt.u8): [rt.u8, rt.u16] => { + const b6: rt.u8 = _212; + return [rt.u8Rem(b6, 16), b6 as rt.u16] as [rt.u8, rt.u16]; + }); + const map: rt.HashMap = rt.hashExtend(rt.hashNew() as rt.HashMap, _9, undefined, undefined, undefined, 234881024); + rt.byteVecPush(out, option_mapOr$02k4ito(rt.hashExtractIfMut(map, (_213: rt.u8, _311: rt.Place): boolean => { + return true; + }).sizeHint()[1], 254, (n: rt.usize): rt.u8 => { + return n & 0xff; + })); + const _19: rt.Iter<[rt.u8, rt.u16]> = rt.hashExtractIfMut(map, (k4: rt.u8, v: rt.Place): boolean => { + v.v = rt.u16Add(v.v, 1); + return rt.u8Rem(k4, keep) === 0; + }); + const taken: rt.BTreeMap = rt.btreeExtend(rt.btreeNew(rt.cmp) as rt.BTreeMap, _19, true, undefined, undefined, "next", 4); + const _24: rt.Iter<[rt.u8, rt.u16]> = rt.iterMap(rt.hashIter(map), (_214: [rt.u8, rt.u16]): [rt.u8, rt.u16] => { + return [_214[0], _214[1]] as [rt.u8, rt.u16]; + }); + const kept: rt.BTreeMap = rt.btreeExtend(rt.btreeNew(rt.cmp) as rt.BTreeMap, _24, true, undefined, undefined, "next", 4); + const iter: rt.Iter<[rt.u8, rt.u16]> = rt.iterChain(rt.iterChain(rt.btreeIter(taken), rt.iterSlice([[255, 65535] as [rt.u8, rt.u16]])), rt.btreeIter(kept)); + while (true) { + const _38: [rt.u8, rt.u16] | rt.Done = iter.next(); + if (_38 === rt.DONE) { + break; + } + rt.byteVecPush(out, _38[0]); + rt.iterExtendBytes(out, rt.iterSlice(rt.u16ToBeBytes(_38[1])), undefined, true); + } + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(rt.iterToOption(rt.hashExtractIfMut(map, (k5: rt.u8, _312: rt.Place): boolean => { + return rt.u8Rem(k5, 2) === 0; + }).next()) !== undefined ? 1 : 0, rt.hashLen(map) & 0xff)), undefined, true); + const _63: rt.Iter<[rt.u8, rt.ByteVec]> = rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_215: rt.u8): [rt.u8, rt.ByteVec] => { + const b7: rt.u8 = _215; + return [rt.u8Rem(b7, 8), rt.byteVecFrom(Uint8Array.of(b7))] as [rt.u8, rt.ByteVec]; + }); + const words: rt.HashMap = rt.hashExtend(rt.hashNew() as rt.HashMap, _63, undefined, undefined, undefined, 58720256); + const _66: rt.Iter<[rt.u8, rt.ByteVec]> = rt.hashExtractIf(words, (k6: rt.u8, v2: rt.ByteVec): boolean => { + rt.byteVecPush(v2, k6); + return rt.u8Rem(v2.data[rt.idx(v2, 0)], keep) === 0; + }); + const iter2: rt.Iter<[rt.u8, rt.ByteVec]> = rt.btreeIter(rt.btreeExtend(rt.btreeNew(rt.cmp) as rt.BTreeMap, _66, true, undefined, undefined, "next", 16)); + while (true) { + const _73: [rt.u8, rt.ByteVec] | rt.Done = iter2.next(); + if (_73 === rt.DONE) { + break; + } + rt.byteVecPush(out, _73[0]); + rt.iterExtendBytes(out, rt.iterSlice(rt.byteVecView(_73[1])), undefined, true); + } + rt.byteVecPush(out, rt.iterSum(rt.iterMap(rt.hashValues(words), (a0: rt.ByteVec): rt.usize => { + return a0.length; + }), rt.usizeAdd, 0) & 0xff); + } else if (_6 === 1) { + const _88: rt.Iter = rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_210: rt.u8): Pair.Pair => { + const b4: rt.u8 = _210; + return { a: rt.u8Rem(b4, 8), b: rt.u8Rem(b4, 3) as rt.u16 }; + }); + const set: rt.HashSet = rt.hashExtendKeys(rt.hashNew(rt.hashing(Pair.hash$Hash_hash_DefaultHasher as (a0: Pair.Pair, a1: rt.Hasher) => undefined, Pair.eq$cmp_PartialEq)) as rt.HashSet, _88, undefined, undefined, 234881024); + const _91: rt.Iter = rt.hashExtractKeysIf(set, (p: Pair.Pair): boolean => { + return rt.u16Rem(p.a as rt.u16, keep as rt.u16) === p.b; + }); + const taken3: rt.BTreeSet = rt.btreeExtendKeys(rt.btreeNew(Pair.cmp$cmp_Ord) as rt.BTreeSet, _91, true, undefined, "next", 4); + const _96: rt.Iter = rt.hashKeys(set); + const kept2: rt.BTreeSet = rt.btreeExtendKeys(rt.btreeNew(Pair.cmp$cmp_Ord) as rt.BTreeSet, _96, true, undefined, "next", 4); + const iter3: rt.Iter = rt.iterChain(rt.iterChain(rt.btreeKeys(taken3), rt.iterSlice([{ a: 255, b: 0 }])), rt.btreeKeys(kept2)); + while (true) { + const _108: Pair.Pair | rt.Done = iter3.next(); + if (_108 === rt.DONE) { + break; + } + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_108.a, _108.b & 0xff)), undefined, true); + } + const _118: rt.Iter = rt.iterSlice(rt.byteSliceView(data)); + const bytes: rt.HashSet = rt.hashExtendKeys(rt.hashNew() as rt.HashSet, _118, undefined, undefined, 469762048); + rt.byteVecPush(out, rt.iterCount(rt.hashExtractKeysIf(bytes, (b5: rt.u8): boolean => { + return rt.u8Rem(b5, keep) === 1; + })) & 0xff); + rt.byteVecPush(out, rt.hashLen(bytes) & 0xff); + rt.byteVecPush(out, rt.iterToOption(rt.hashExtractKeysIf(bytes, (_211: rt.u8): boolean => { + return false; + }).next()) === undefined ? 1 : 0); + } else { + const _140: rt.Iter<[Clash.Clash, Tally.Tally]> = rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_2: rt.u8): [Clash.Clash, Tally.Tally] => { + const b2: rt.u8 = _2; + return [{ _0: rt.u8Rem(b2, 8) }, { n: b2 as rt.u16 }] as [Clash.Clash, Tally.Tally]; + }); + const map2: rt.HashMap = rt.hashExtend(rt.hashNew(rt.hashing(Clash.hash$Hash_hash_DefaultHasher as (a0: Clash.Clash, a1: rt.Hasher) => undefined, Clash.eq$cmp_PartialEq)) as rt.HashMap, _140, undefined, undefined, undefined, 234881024); + const _143: rt.Iter<[rt.u8, rt.u16]> = rt.iterMap(rt.hashExtractIf(map2, (k2: Clash.Clash, t: Tally.Tally): boolean => { + t.n = rt.u16Add(t.n, k2._0 as rt.u16); + return rt.u16Rem(t.n, keep as rt.u16) === 0; + }), (_22: [Clash.Clash, Tally.Tally]): [rt.u8, rt.u16] => { + return [_22[0]._0, _22[1].n] as [rt.u8, rt.u16]; + }); + const taken4: rt.BTreeMap = rt.btreeExtend(rt.btreeNew(rt.cmp) as rt.BTreeMap, _143, true, undefined, undefined, "next", 4); + const _149: rt.Iter<[rt.u8, rt.u16]> = rt.iterMap(rt.hashIter(map2), (_23: [Clash.Clash, Tally.Tally]): [rt.u8, rt.u16] => { + return [_23[0]._0, _23[1].n] as [rt.u8, rt.u16]; + }); + const kept3: rt.BTreeMap = rt.btreeExtend(rt.btreeNew(rt.cmp) as rt.BTreeMap, _149, true, undefined, undefined, "next", 4); + const iter4: rt.Iter<[rt.u8, rt.u16]> = rt.iterChain(rt.iterChain(rt.btreeIter(taken4), rt.iterSlice([[255, 65535] as [rt.u8, rt.u16]])), rt.btreeIter(kept3)); + while (true) { + const _163: [rt.u8, rt.u16] | rt.Done = iter4.next(); + if (_163 === rt.DONE) { + break; + } + rt.byteVecPush(out, _163[0]); + rt.iterExtendBytes(out, rt.iterSlice(rt.u16ToBeBytes(_163[1])), undefined, true); + } + let iterStart: rt.u8 = 0; + const iterEnd: rt.u8 = 8; + while ((_176 = iterStart++) < iterEnd) { + rt.byteVecPush(out, option_mapOr$1ht002r(rt.hashGet(map2, { _0: _176 }), 238, (t3: Tally.Tally): rt.u8 => { + return t3.n & 0xff; + })); + } + const _187: rt.Iter = rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_26: rt.u8): Clash.Clash => { + return { _0: rt.u8Rem(_26, 6) }; + }); + const set2: rt.HashSet = rt.hashExtendKeys(rt.hashNew(rt.hashing(Clash.hash$Hash_hash_DefaultHasher as (a0: Clash.Clash, a1: rt.Hasher) => undefined, Clash.eq$cmp_PartialEq)) as rt.HashSet, _187, undefined, undefined, 469762048); + rt.byteVecPush(out, rt.iterCount(rt.hashExtractKeysIf(set2, (c: Clash.Clash): boolean => { + return rt.u8Rem(c._0, keep) === 0; + })) & 0xff); + const kept4: rt.ByteVec = rt.iterToByteVec(rt.iterMap(rt.hashKeys(set2), (c2: Clash.Clash): rt.u8 => { + return c2._0; + }), "next"); + rt.byteSliceView(rt.byteVecSlice(kept4)).sort(); + rt.iterExtendBytes(out, rt.byteVecIntoIter(kept4), undefined, true); + rt.byteVecPush(out, rt.hashContains(set2, { _0: 0 }) ? 1 : 0); + } +} + //# sourceMappingURL=collections.ts.map diff --git a/ts/fixtures/lang/collections/expected/lib.ts b/ts/fixtures/lang/collections/expected/lib.ts index cb390a238..9b638ec66 100644 --- a/ts/fixtures/lang/collections/expected/lib.ts +++ b/ts/fixtures/lang/collections/expected/lib.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rt from "./rt.ts"; -import { hashMaps, sets, btreeMaps, deques, dequeRanges, vecs, stores, optionals, setOps, unlikeEqs, ownNes, cellEqs, unlikeCompares, refOrders } from "./collections.ts"; +import { hashMaps, sets, btreeMaps, deques, dequeRanges, vecs, stores, optionals, setOps, unlikeEqs, ownNes, cellEqs, unlikeCompares, refOrders, extracts } from "./collections.ts"; import type * as Bumped from "./collections.Bumped.ts"; import type * as Picky from "./collections.Picky.ts"; import type * as Quirky from "./collections.Quirky.ts"; @@ -71,7 +71,7 @@ export function cases(): [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) vecs(data2, out2); }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::stores", (_212: rt.u8, data3: rt.ByteSlice, out3: rt.ByteVec): undefined => { stores(data3, out3); - }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::optionals", optionals as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::set_ops", setOps as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::unlike_eqs", unlikeEqs as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::own_nes", ownNes as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::cell_eqs", cellEqs as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::unlike_compares", unlikeCompares as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::ref_orders", refOrders as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::deque_ranges", dequeRanges as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]]; + }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::optionals", optionals as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::set_ops", setOps as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::unlike_eqs", unlikeEqs as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::own_nes", ownNes as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::cell_eqs", cellEqs as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::unlike_compares", unlikeCompares as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::ref_orders", refOrders as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::deque_ranges", dequeRanges as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["collections::extracts", extracts as (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]]; } //# sourceMappingURL=lib.ts.map diff --git a/ts/fixtures/lang/collections/src/collections.rs b/ts/fixtures/lang/collections/src/collections.rs index 9617ea76e..5154d1280 100644 --- a/ts/fixtures/lang/collections/src/collections.rs +++ b/ts/fixtures/lang/collections/src/collections.rs @@ -2110,3 +2110,90 @@ pub fn ref_orders(_kind: u8, data: &[u8], out: &mut Vec) { keys!(by_val.iter().collect(), out); keys!(mixed.iter().collect(), out); } + +/// `extract_if` of hash maps and sets: what its closure takes out, by keys JS compares as +/// they are and keys found by their `Hash`, all colliding, with values changed in place as +/// each is read, and what stays, each sorted. Read part way, it takes out only what it +/// read, and the rest stays. +pub fn extracts(kind: u8, data: &[u8], out: &mut Vec) { + let keep = data.first().map_or(2, |b| b % 3 + 2); + match kind % 3 { + 0 => { + let mut map: HashMap = data.iter().map(|&b| (b % 16, u16::from(b))).collect(); + out.push(map.extract_if(|_, _| true).size_hint().1.map_or(0xfe, |n| n as u8)); + let taken: BTreeMap = map + .extract_if(|k, v| { + *v += 1; + k % keep == 0 + }) + .collect(); + let kept: BTreeMap = map.iter().map(|(k, v)| (*k, *v)).collect(); + for (k, v) in taken.iter().chain([(&0xff, &0xffff)]).chain(&kept) { + out.push(*k); + out.extend(v.to_be_bytes()); + } + let mut it = map.extract_if(|k, _| k % 2 == 0); + let some = it.next().is_some(); + drop(it); + out.extend([some as u8, map.len() as u8]); + let mut words: HashMap> = data.iter().map(|&b| (b % 8, vec![b])).collect(); + let taken: BTreeMap> = words + .extract_if(|k, v| { + v.push(*k); + v[0] % keep == 0 + }) + .collect(); + for (k, v) in &taken { + out.push(*k); + out.extend(v); + } + out.push(words.values().map(Vec::len).sum::() as u8); + } + 1 => { + let mut set: HashSet = data + .iter() + .map(|&b| Pair { + a: b % 8, + b: u16::from(b % 3), + }) + .collect(); + let taken: BTreeSet = set.extract_if(|p| u16::from(p.a) % u16::from(keep) == p.b).collect(); + let kept: BTreeSet = set.iter().copied().collect(); + for p in taken.iter().chain([&Pair { a: 0xff, b: 0 }]).chain(&kept) { + out.extend([p.a, p.b as u8]); + } + let mut bytes: HashSet = data.iter().copied().collect(); + out.push(bytes.extract_if(|b| b % keep == 1).count() as u8); + out.push(bytes.len() as u8); + out.push(bytes.extract_if(|_| false).next().is_none() as u8); + } + _ => { + // Keys that all collide, chained in one slot, and taken from any place in it. + let mut map: HashMap = data + .iter() + .map(|&b| (Clash(b % 8), Tally { n: u16::from(b) })) + .collect(); + let taken: BTreeMap = map + .extract_if(|k, t| { + t.n += u16::from(k.0); + t.n % u16::from(keep) == 0 + }) + .map(|(k, t)| (k.0, t.n)) + .collect(); + let kept: BTreeMap = map.iter().map(|(k, t)| (k.0, t.n)).collect(); + for (k, v) in taken.iter().chain([(&0xff, &0xffff)]).chain(&kept) { + out.push(*k); + out.extend(v.to_be_bytes()); + } + for k in 0..8 { + out.push(map.get(&Clash(k)).map_or(0xee, |t| t.n as u8)); + } + let mut set: HashSet = data.iter().map(|&b| Clash(b % 6)).collect(); + out.push(set.extract_if(|c| c.0 % keep == 0).count() as u8); + let mut kept: Vec = set.iter().map(|c| c.0).collect(); + kept.sort(); + out.extend(kept); + out.push(set.contains(&Clash(0)) as u8); + } + } +} diff --git a/ts/fixtures/lang/collections/src/lib.rs b/ts/fixtures/lang/collections/src/lib.rs index 04d8de931..47c48ebbc 100644 --- a/ts/fixtures/lang/collections/src/lib.rs +++ b/ts/fixtures/lang/collections/src/lib.rs @@ -30,5 +30,6 @@ fn cases() -> Vec<(&'static str, Case)> { ("collections::unlike_compares", collections::unlike_compares), ("collections::ref_orders", collections::ref_orders), ("collections::deque_ranges", collections::deque_ranges), + ("collections::extracts", collections::extracts), ] } diff --git a/ts/fixtures/lang/shapes/expected/fmt.ts b/ts/fixtures/lang/shapes/expected/fmt.ts index 6ec983f8a..ee85d7042 100644 --- a/ts/fixtures/lang/shapes/expected/fmt.ts +++ b/ts/fixtures/lang/shapes/expected/fmt.ts @@ -3483,6 +3483,26 @@ export function sources(data: rt.ByteSlice, out: rt.ByteVec): void { }); const args42: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtAdaptor(part17, f, "Map", (value: rt.Iter, f: rt.Formatter) => rt.fmtChain(value, f, (value: rt.Iter, f: rt.Formatter) => rt.fmtIterOption(value, f, rt.u8Debug, [["Once", "inner"], ["IntoIter", "inner"], ["Item", "opt"]]), (value: rt.Iter, f: rt.Formatter) => rt.fmtIter(value, f, rt.u8Debug, ["IntoIter"])))]; put(out, rt.fmtFormat([args42[0], "|", rt.fmtSpec({ alternate: true }, args42[0])])); + const part18 = rt.iterRepeat(b); + const args44: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtRepeat(part18, f, rt.u8Debug)]; + put(out, rt.fmtFormat([args44[0], "|", rt.fmtSpec({ alternate: true }, args44[0]), "|", rt.fmtSpec({ debugHex: "x" }, args44[0])])); + const part19 = ends$sources_iter_Take_iter_Repeat_fmt_Pair(rt.iterTake(rt.iterRepeat({ _0: b, _1: 7 }), 3), front, back); + const args46: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtCounted(part19, f, "Take", (value: rt.Iter, f: rt.Formatter) => rt.fmtRepeat(value, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f)))]; + put(out, rt.fmtFormat([args46[0]])); + const n2: rt.usize = rt.u8Rem(at(3), 4) as rt.usize; + const part20 = ends$sources_iter_RepeatN_u8(rt.iterRepeatN(b, n2), front, back); + const args48: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtRepeatN(part20, f, rt.u8Debug)]; + put(out, rt.fmtFormat([args48[0], "|", rt.fmtSpec({ alternate: true }, args48[0])])); + const it12: rt.Iter = rt.iterRepeatN({ _0: b, _1: 8 }, n2); + const _464: rt.usize = rt.u8Rem(at(4), 4) as rt.usize; + rt.iterNth(it12, _464); + const args50: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtRepeatN(it12, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f))]; + put(out, rt.fmtFormat([args50[0], "|", rt.fmtSpec({ alternate: true }, args50[0])])); + const part21 = ends$sources_iter_OnceWith_fmt_sources_closure6(rt.iterOnceWith((): rt.u8 => { + return b; + }), rt.usizeRem(front, 2), rt.usizeRem(back, 2)); + const args52: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOnceWith(part21, f)]; + put(out, rt.fmtFormat([args52[0], "|", rt.fmtSpec({ alternate: true }, args52[0]), "|", rt.fmtSpec({ align: ">", width: 20 }, args52[0])])); const text: string = rt.stringExtendChars("", rt.iterMap(rt.iterSlice(rt.byteSliceView(bytes)), (_212: rt.u8): rt.char => { const _54: rt.usize = rt.u8Rem(_212, 5) as rt.usize; if (!(_54 < 5)) { @@ -3490,144 +3510,144 @@ export function sources(data: rt.ByteSlice, out: rt.ByteVec): void { } return [97, 233, 20013, 129408, 10][_54]; })); - const part18 = ends$sources_str_CharIndices(rt.strCharIndices(text), front, back); - const args44: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtCharIndices(part18, f)]; - put(out, rt.fmtFormat([args44[0], "|", rt.fmtSpec({ alternate: true }, args44[0]), "|", rt.fmtSpec({ debugHex: "x" }, args44[0])])); + const part22 = ends$sources_str_CharIndices(rt.strCharIndices(text), front, back); + const args54: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtCharIndices(part22, f)]; + put(out, rt.fmtFormat([args54[0], "|", rt.fmtSpec({ alternate: true }, args54[0]), "|", rt.fmtSpec({ debugHex: "x" }, args54[0])])); let drained: string = text; - const it11: rt.Iter = ends$sources_string_Drain(rt.stringDrain(rt.place(() => drained, (value3) => drained = value3), undefined), front, back); - const args46: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtStringDrain(it11, f)]; - put(out, rt.fmtFormat([args46[0], "|", rt.fmtSpec({ alternate: true }, args46[0])])); - rt.drop(it11); + const it15: rt.Iter = ends$sources_string_Drain(rt.stringDrain(rt.place(() => drained, (value3) => drained = value3), undefined), front, back); + const args56: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtStringDrain(it15, f)]; + put(out, rt.fmtFormat([args56[0], "|", rt.fmtSpec({ alternate: true }, args56[0])])); + rt.drop(it15); const size: rt.usize = rt.usizeAdd(rt.u8Rem(at(3), 4) as rt.usize, 1); - const part19 = ends$sources_slice_Windows_u8(rt.byteSliceWindows(bytes, size), front, back); - const args48: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part19, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; - put(out, rt.fmtFormat([args48[0], "|", rt.fmtSpec({ alternate: true }, args48[0]), "|", rt.fmtSpec({ debugHex: "x" }, args48[0])])); - const it13: rt.Iter = rt.byteSliceWindows(bytes, size); - const _473: rt.usize = rt.u8Rem(at(4), 8) as rt.usize; - rt.iterNth(it13, _473); - const args50: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it13, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; - put(out, rt.fmtFormat([args50[0]])); - const it14: rt.Iter = fronts$sources_slice_Windows_u8(rt.byteSliceWindows(bytes, size), 8); - const args52: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it14, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; - put(out, rt.fmtFormat([args52[0]])); - rt.iterToOption(it14.nextBack()); - const args54: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it14, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; - put(out, rt.fmtFormat([args54[0]])); - const it15: rt.Iter = rt.byteSliceWindows(bytes, size); - const _522: rt.usize = rt.u8Rem(at(4), 8) as rt.usize; - rt.iterNthBack(it15, _522); - const args56: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it15, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; - put(out, rt.fmtFormat([args56[0]])); + const part23 = ends$sources_slice_Windows_u8(rt.byteSliceWindows(bytes, size), front, back); + const args58: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part23, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; + put(out, rt.fmtFormat([args58[0], "|", rt.fmtSpec({ alternate: true }, args58[0]), "|", rt.fmtSpec({ debugHex: "x" }, args58[0])])); + const it17: rt.Iter = rt.byteSliceWindows(bytes, size); + const _564: rt.usize = rt.u8Rem(at(4), 8) as rt.usize; + rt.iterNth(it17, _564); + const args60: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it17, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; + put(out, rt.fmtFormat([args60[0]])); + const it18: rt.Iter = fronts$sources_slice_Windows_u8(rt.byteSliceWindows(bytes, size), 8); + const args62: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it18, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; + put(out, rt.fmtFormat([args62[0]])); + rt.iterToOption(it18.nextBack()); + const args64: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it18, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; + put(out, rt.fmtFormat([args64[0]])); + const it19: rt.Iter = rt.byteSliceWindows(bytes, size); + const _613: rt.usize = rt.u8Rem(at(4), 8) as rt.usize; + rt.iterNthBack(it19, _613); + const args66: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it19, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Windows")]; + put(out, rt.fmtFormat([args66[0]])); const wide: rt.u16[] = rt.iterToArray(rt.iterMap(rt.iterSlice(rt.byteSliceView(bytes)), (_213: rt.u8): rt.u16 => { return rt.u16Mul(_213 as rt.u16, 257); }), undefined, 2, true); - const part20 = ends$sources_slice_Windows_u16(rt.sliceWindows(wide, size), front, back); - const args58: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part20, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "Windows")]; - put(out, rt.fmtFormat([args58[0], "|", rt.fmtSpec({ alternate: true, debugHex: "x" }, args58[0])])); - const part21 = ends$sources_slice_Chunks_u8(rt.byteSliceChunks(bytes, size), front, back); - const args60: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part21, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Chunks")]; - put(out, rt.fmtFormat([args60[0], "|", rt.fmtSpec({ alternate: true }, args60[0])])); - const part22 = ends$sources_slice_ChunksExact_u16(rt.sliceChunksExact(wide, size), front, back); - const args62: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part22, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "ChunksExact")]; - put(out, rt.fmtFormat([args62[0], "|", rt.fmtSpec({ alternate: true }, args62[0])])); - const part23 = ends$sources_slice_ChunksExact_u8(rt.byteSliceChunksExact(bytes, size), front, back); - const args64: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part23, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "ChunksExact")]; - put(out, rt.fmtFormat([args64[0]])); - const part24 = ends$sources_slice_RChunks_u16(rt.sliceRchunks(wide, size), front, back); - const args66: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part24, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "RChunks")]; - put(out, rt.fmtFormat([args66[0]])); - const part25 = ends$sources_slice_RChunks_u8(rt.byteSliceRchunks(bytes, size), front, back); - const args68: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part25, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RChunks")]; - put(out, rt.fmtFormat([args68[0], "|", rt.fmtSpec({ alternate: true }, args68[0])])); - const part26 = ends$sources_slice_RChunksExact_u8(rt.byteSliceRchunksExact(bytes, size), front, back); - const args70: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part26, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RChunksExact")]; - put(out, rt.fmtFormat([args70[0]])); - const it23: rt.Iter = rt.sliceRchunksExact(wide, size); - const _652: rt.usize = rt.u8Rem(at(4), 4) as rt.usize; - rt.iterNth(it23, _652); - const args72: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it23, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "RChunksExact")]; - put(out, rt.fmtFormat([args72[0]])); - const part27 = ends$sources_slice_Split_u8_fmt_sources_closure8(rt.byteSliceSplit(bytes, (x5: rt.u8): boolean => { + const part24 = ends$sources_slice_Windows_u16(rt.sliceWindows(wide, size), front, back); + const args68: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part24, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "Windows")]; + put(out, rt.fmtFormat([args68[0], "|", rt.fmtSpec({ alternate: true, debugHex: "x" }, args68[0])])); + const part25 = ends$sources_slice_Chunks_u8(rt.byteSliceChunks(bytes, size), front, back); + const args70: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part25, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Chunks")]; + put(out, rt.fmtFormat([args70[0], "|", rt.fmtSpec({ alternate: true }, args70[0])])); + const part26 = ends$sources_slice_ChunksExact_u16(rt.sliceChunksExact(wide, size), front, back); + const args72: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part26, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "ChunksExact")]; + put(out, rt.fmtFormat([args72[0], "|", rt.fmtSpec({ alternate: true }, args72[0])])); + const part27 = ends$sources_slice_ChunksExact_u8(rt.byteSliceChunksExact(bytes, size), front, back); + const args74: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part27, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "ChunksExact")]; + put(out, rt.fmtFormat([args74[0]])); + const part28 = ends$sources_slice_RChunks_u16(rt.sliceRchunks(wide, size), front, back); + const args76: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part28, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "RChunks")]; + put(out, rt.fmtFormat([args76[0]])); + const part29 = ends$sources_slice_RChunks_u8(rt.byteSliceRchunks(bytes, size), front, back); + const args78: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part29, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RChunks")]; + put(out, rt.fmtFormat([args78[0], "|", rt.fmtSpec({ alternate: true }, args78[0])])); + const part30 = ends$sources_slice_RChunksExact_u8(rt.byteSliceRchunksExact(bytes, size), front, back); + const args80: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(part30, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RChunksExact")]; + put(out, rt.fmtFormat([args80[0]])); + const it27: rt.Iter = rt.sliceRchunksExact(wide, size); + const _743: rt.usize = rt.u8Rem(at(4), 4) as rt.usize; + rt.iterNth(it27, _743); + const args82: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtParts(it27, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "RChunksExact")]; + put(out, rt.fmtFormat([args82[0]])); + const part31 = ends$sources_slice_Split_u8_fmt_sources_closure9(rt.byteSliceSplit(bytes, (x5: rt.u8): boolean => { return rt.u8Rem(x5, 3) === 0; }), front, back); - const args74: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part27, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Split", false)]; - put(out, rt.fmtFormat([args74[0], "|", rt.fmtSpec({ alternate: true }, args74[0]), "|", rt.fmtSpec({ debugHex: "x" }, args74[0])])); - const part28 = ends$sources_slice_SplitInclusive_u8_fmt_sources_closure8(rt.byteSliceSplitInclusive(bytes, (x6: rt.u8): boolean => { + const args84: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part31, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Split", false)]; + put(out, rt.fmtFormat([args84[0], "|", rt.fmtSpec({ alternate: true }, args84[0]), "|", rt.fmtSpec({ debugHex: "x" }, args84[0])])); + const part32 = ends$sources_slice_SplitInclusive_u8_fmt_sources_closure9(rt.byteSliceSplitInclusive(bytes, (x6: rt.u8): boolean => { return rt.u8Rem(x6, 3) === 0; }), front, back); - const args76: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part28, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "SplitInclusive", false)]; - put(out, rt.fmtFormat([args76[0]])); - const part29 = ends$sources_slice_RSplit_u8_fmt_sources_closure8(rt.byteSliceRsplit(bytes, (x7: rt.u8): boolean => { + const args86: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part32, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "SplitInclusive", false)]; + put(out, rt.fmtFormat([args86[0]])); + const part33 = ends$sources_slice_RSplit_u8_fmt_sources_closure9(rt.byteSliceRsplit(bytes, (x7: rt.u8): boolean => { return rt.u8Rem(x7, 3) === 0; }), front, back); - const args78: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part29, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RSplit", false)]; - put(out, rt.fmtFormat([args78[0]])); - const part30 = fronts$sources_slice_SplitN_u8_fmt_sources_closure8(rt.byteSliceSplitn(bytes, rt.u8Rem(at(4), 4) as rt.usize, (x8: rt.u8): boolean => { + const args88: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part33, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RSplit", false)]; + put(out, rt.fmtFormat([args88[0]])); + const part34 = fronts$sources_slice_SplitN_u8_fmt_sources_closure9(rt.byteSliceSplitn(bytes, rt.u8Rem(at(4), 4) as rt.usize, (x8: rt.u8): boolean => { return rt.u8Rem(x8, 3) === 0; }), front); - const args80: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part30, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Split", false, "SplitN")]; - put(out, rt.fmtFormat([args80[0], "|", rt.fmtSpec({ alternate: true }, args80[0])])); - const part31 = fronts$sources_slice_RSplitN_u8_fmt_sources_closure8(rt.byteSliceRsplitn(bytes, 2, (x9: rt.u8): boolean => { + const args90: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part34, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "Split", false, "SplitN")]; + put(out, rt.fmtFormat([args90[0], "|", rt.fmtSpec({ alternate: true }, args90[0])])); + const part35 = fronts$sources_slice_RSplitN_u8_fmt_sources_closure9(rt.byteSliceRsplitn(bytes, 2, (x9: rt.u8): boolean => { return rt.u8Rem(x9, 3) === 0; }), front); - const args82: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part31, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RSplit", false, "RSplitN")]; - put(out, rt.fmtFormat([args82[0]])); - const part32 = ends$sources_slice_Split_u16_fmt_sources_closure9(rt.sliceSplit(wide, (x10: rt.u16): boolean => { + const args92: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part35, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RSplit", false, "RSplitN")]; + put(out, rt.fmtFormat([args92[0]])); + const part36 = ends$sources_slice_Split_u16_fmt_sources_closure10(rt.sliceSplit(wide, (x10: rt.u16): boolean => { return rt.u16Rem(x10, 3) === 0; }), front, back); - const args84: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part32, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "Split", false)]; - put(out, rt.fmtFormat([args84[0]])); - const part33 = fronts$sources_slice_SplitN_u16_fmt_sources_closure9(rt.sliceSplitn(wide, 2, (x11: rt.u16): boolean => { + const args94: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part36, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "Split", false)]; + put(out, rt.fmtFormat([args94[0]])); + const part37 = fronts$sources_slice_SplitN_u16_fmt_sources_closure10(rt.sliceSplitn(wide, 2, (x11: rt.u16): boolean => { return rt.u16Rem(x11, 3) === 0; }), front); - const args86: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part33, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "Split", false, "SplitN")]; - put(out, rt.fmtFormat([args86[0]])); + const args96: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part37, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "Split", false, "SplitN")]; + put(out, rt.fmtFormat([args96[0]])); const owned: rt.ByteVec = rt.byteSliceToByteVec(bytes); - const part34 = ends$sources_slice_SplitMut_u8_fmt_sources_closure8(rt.byteSliceSplit(rt.byteVecSlice(owned), (x12: rt.u8): boolean => { + const part38 = ends$sources_slice_SplitMut_u8_fmt_sources_closure9(rt.byteSliceSplit(rt.byteVecSlice(owned), (x12: rt.u8): boolean => { return rt.u8Rem(x12, 3) === 0; }), front, back); - const args88: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part34, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "SplitMut", true)]; - put(out, rt.fmtFormat([args88[0], "|", rt.fmtSpec({ alternate: true }, args88[0])])); - const part35 = ends$sources_slice_SplitInclusiveMut_u8_fmt_sources_closure8(rt.byteSliceSplitInclusive(rt.byteVecSlice(owned), (x13: rt.u8): boolean => { + const args98: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part38, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "SplitMut", true)]; + put(out, rt.fmtFormat([args98[0], "|", rt.fmtSpec({ alternate: true }, args98[0])])); + const part39 = ends$sources_slice_SplitInclusiveMut_u8_fmt_sources_closure9(rt.byteSliceSplitInclusive(rt.byteVecSlice(owned), (x13: rt.u8): boolean => { return rt.u8Rem(x13, 3) === 0; }), front, back); - const args90: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part35, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "SplitInclusiveMut", true)]; - put(out, rt.fmtFormat([args90[0]])); - const part36 = ends$sources_slice_RSplitMut_u8_fmt_sources_closure8(rt.byteSliceRsplit(rt.byteVecSlice(owned), (x14: rt.u8): boolean => { + const args100: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part39, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "SplitInclusiveMut", true)]; + put(out, rt.fmtFormat([args100[0]])); + const part40 = ends$sources_slice_RSplitMut_u8_fmt_sources_closure9(rt.byteSliceRsplit(rt.byteVecSlice(owned), (x14: rt.u8): boolean => { return rt.u8Rem(x14, 3) === 0; }), front, back); - const args92: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part36, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RSplitMut", true)]; - put(out, rt.fmtFormat([args92[0]])); - const part37 = fronts$sources_slice_SplitNMut_u8_fmt_sources_closure8(rt.byteSliceSplitn(rt.byteVecSlice(owned), 2, (x15: rt.u8): boolean => { + const args102: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part40, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RSplitMut", true)]; + put(out, rt.fmtFormat([args102[0]])); + const part41 = fronts$sources_slice_SplitNMut_u8_fmt_sources_closure9(rt.byteSliceSplitn(rt.byteVecSlice(owned), 2, (x15: rt.u8): boolean => { return rt.u8Rem(x15, 3) === 0; }), front); - const args94: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part37, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "SplitMut", true, "SplitNMut")]; - put(out, rt.fmtFormat([args94[0]])); - const part38 = fronts$sources_slice_RSplitNMut_u8_fmt_sources_closure8(rt.byteSliceRsplitn(rt.byteVecSlice(owned), rt.u8Rem(at(4), 4) as rt.usize, (x16: rt.u8): boolean => { + const args104: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part41, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "SplitMut", true, "SplitNMut")]; + put(out, rt.fmtFormat([args104[0]])); + const part42 = fronts$sources_slice_RSplitNMut_u8_fmt_sources_closure9(rt.byteSliceRsplitn(rt.byteVecSlice(owned), rt.u8Rem(at(4), 4) as rt.usize, (x16: rt.u8): boolean => { return rt.u8Rem(x16, 3) === 0; }), front); - const args96: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part38, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RSplitMut", true, "RSplitNMut")]; - put(out, rt.fmtFormat([args96[0]])); - const part39 = ends$sources_slice_SplitMut_u16_fmt_sources_closure9(rt.sliceSplitMut(rt.vecExact(wide.slice(), 2), (x17: rt.u16): boolean => { + const args106: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part42, f, (value: rt.ByteSlice, f: rt.Formatter) => rt.fmtList(rt.byteSliceView(value), f, rt.u8Debug), "RSplitMut", true, "RSplitNMut")]; + put(out, rt.fmtFormat([args106[0]])); + const part43 = ends$sources_slice_SplitMut_u16_fmt_sources_closure10(rt.sliceSplitMut(rt.vecExact(wide.slice(), 2), (x17: rt.u16): boolean => { return rt.u16Rem(x17, 3) === 0; }), front, back); - const args98: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part39, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "SplitMut", true)]; - put(out, rt.fmtFormat([args98[0]])); - const _885: [rt.HashSet, rt.HashSet] = [rt.hashNew() as rt.HashSet, rt.hashNew() as rt.HashSet]; - const one: rt.HashSet = _885[0]; - const other: rt.HashSet = _885[1]; + const args108: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSplit(part43, f, (value: rt.u16[], f: rt.Formatter) => rt.fmtList(value, f, rt.u16Debug), "SplitMut", true)]; + put(out, rt.fmtFormat([args108[0]])); + const _976: [rt.HashSet, rt.HashSet] = [rt.hashNew() as rt.HashSet, rt.hashNew() as rt.HashSet]; + const one: rt.HashSet = _976[0]; + const other: rt.HashSet = _976[1]; if (rt.u8Rem(b, 2) === 0) { rt.hashAdd(one, b); } if (rt.u8Rem(b, 3) === 0) { rt.hashAdd(other, b); } - const _906: rt.Iter = rt.hashDifference(one, other); - const _910: rt.Iter = rt.hashIntersection(one, other); - const _914: rt.Iter = rt.hashSymmetricDifference(one, other); - const _918: rt.Iter = rt.hashUnion(one, other); - const args100: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterClone(_906, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtIterClone(_910, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtIterClone(_914, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtIterClone(_918, f, rt.u8Debug)]; - put(out, rt.fmtFormat([args100[0], "|", rt.fmtSpec({ alternate: true }, args100[1]), "|", args100[2], "|", args100[3]])); + const _997: rt.Iter = rt.hashDifference(one, other); + const _1001: rt.Iter = rt.hashIntersection(one, other); + const _1005: rt.Iter = rt.hashSymmetricDifference(one, other); + const _1009: rt.Iter = rt.hashUnion(one, other); + const args110: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterClone(_997, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtIterClone(_1001, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtIterClone(_1005, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtIterClone(_1009, f, rt.u8Debug)]; + put(out, rt.fmtFormat([args110[0], "|", rt.fmtSpec({ alternate: true }, args110[1]), "|", args110[2], "|", args110[3]])); } export function ends$sources_array_IntoIter_fmt_Pair_2(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { @@ -3662,6 +3682,54 @@ export function ends$sources_array_IntoIter_u8_4(it: rt.Iter, front: rt.u } } +export function ends$sources_iter_OnceWith_fmt_sources_closure6(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (iterStart++ < iterEnd) { + rt.iterToOption(it.next()); + } + let iterStart2: rt.usize = 0; + const iterEnd2: rt.usize = back; + while (true) { + if (!(iterStart2++ < iterEnd2)) { + return it; + } + rt.iterToOption(it.nextBack()); + } +} + +export function ends$sources_iter_RepeatN_u8(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (iterStart++ < iterEnd) { + rt.iterToOption(it.next()); + } + let iterStart2: rt.usize = 0; + const iterEnd2: rt.usize = back; + while (true) { + if (!(iterStart2++ < iterEnd2)) { + return it; + } + rt.iterToOption(it.nextBack()); + } +} + +export function ends$sources_iter_Take_iter_Repeat_fmt_Pair(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (iterStart++ < iterEnd) { + rt.iterToOption(it.next()); + } + let iterStart2: rt.usize = 0; + const iterEnd2: rt.usize = back; + while (true) { + if (!(iterStart2++ < iterEnd2)) { + return it; + } + rt.iterToOption(it.nextBack()); + } +} + export function ends$sources_slice_ChunksExact_u16(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; @@ -3758,7 +3826,7 @@ export function ends$sources_slice_RChunks_u8(it: rt.Iter, front: } } -export function ends$sources_slice_RSplitMut_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { +export function ends$sources_slice_RSplitMut_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (iterStart++ < iterEnd) { @@ -3774,7 +3842,7 @@ export function ends$sources_slice_RSplitMut_u8_fmt_sources_closure8(it: rt.Iter } } -export function ends$sources_slice_RSplit_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { +export function ends$sources_slice_RSplit_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (iterStart++ < iterEnd) { @@ -3790,7 +3858,7 @@ export function ends$sources_slice_RSplit_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { +export function ends$sources_slice_SplitInclusiveMut_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (iterStart++ < iterEnd) { @@ -3806,7 +3874,7 @@ export function ends$sources_slice_SplitInclusiveMut_u8_fmt_sources_closure8(it: } } -export function ends$sources_slice_SplitInclusive_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { +export function ends$sources_slice_SplitInclusive_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (iterStart++ < iterEnd) { @@ -3822,7 +3890,7 @@ export function ends$sources_slice_SplitInclusive_u8_fmt_sources_closure8(it: rt } } -export function ends$sources_slice_SplitMut_u16_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { +export function ends$sources_slice_SplitMut_u16_fmt_sources_closure10(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (iterStart++ < iterEnd) { @@ -3838,7 +3906,7 @@ export function ends$sources_slice_SplitMut_u16_fmt_sources_closure9(it: rt.Iter } } -export function ends$sources_slice_SplitMut_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { +export function ends$sources_slice_SplitMut_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (iterStart++ < iterEnd) { @@ -3854,7 +3922,7 @@ export function ends$sources_slice_SplitMut_u8_fmt_sources_closure8(it: rt.Iter< } } -export function ends$sources_slice_Split_u16_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { +export function ends$sources_slice_Split_u16_fmt_sources_closure10(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (iterStart++ < iterEnd) { @@ -3870,7 +3938,7 @@ export function ends$sources_slice_Split_u16_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { +export function ends$sources_slice_Split_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize, back: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (iterStart++ < iterEnd) { @@ -4027,7 +4095,7 @@ export function fronts$sources_result_IterMut_fmt_Pair(it: rt.Iter, f } } -export function fronts$sources_slice_RSplitNMut_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize): rt.Iter { +export function fronts$sources_slice_RSplitNMut_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (true) { @@ -4038,7 +4106,7 @@ export function fronts$sources_slice_RSplitNMut_u8_fmt_sources_closure8(it: rt.I } } -export function fronts$sources_slice_RSplitN_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize): rt.Iter { +export function fronts$sources_slice_RSplitN_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (true) { @@ -4049,7 +4117,7 @@ export function fronts$sources_slice_RSplitN_u8_fmt_sources_closure8(it: rt.Iter } } -export function fronts$sources_slice_SplitNMut_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize): rt.Iter { +export function fronts$sources_slice_SplitNMut_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (true) { @@ -4060,7 +4128,7 @@ export function fronts$sources_slice_SplitNMut_u8_fmt_sources_closure8(it: rt.It } } -export function fronts$sources_slice_SplitN_u16_fmt_sources_closure9(it: rt.Iter, front: rt.usize): rt.Iter { +export function fronts$sources_slice_SplitN_u16_fmt_sources_closure10(it: rt.Iter, front: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (true) { @@ -4071,7 +4139,7 @@ export function fronts$sources_slice_SplitN_u16_fmt_sources_closure9(it: rt.Iter } } -export function fronts$sources_slice_SplitN_u8_fmt_sources_closure8(it: rt.Iter, front: rt.usize): rt.Iter { +export function fronts$sources_slice_SplitN_u8_fmt_sources_closure9(it: rt.Iter, front: rt.usize): rt.Iter { let iterStart: rt.usize = 0; const iterEnd: rt.usize = front; while (true) { @@ -4093,4 +4161,180 @@ export function fronts$sources_slice_Windows_u8(it: rt.Iter, front } } +/** + * A `BTreeSet`'s set operations' `Debug`, each the way std picked to make it and what that + * reads: merged, each key of the smaller looked up in a set 16 times its size, or answered + * by where the sets meet, fresh and part read, plain and pretty. And each `ExtractIf`'s: a + * list's the item it reads next, a hash map's and set's nothing. + */ +export function sets(data: rt.ByteSlice, out: rt.ByteVec): void { + const at: (a0: rt.usize) => rt.u8 = (i: rt.usize): rt.u8 => { + return option_unwrapOr$0r2bmpr(rt.byteSliceGet(data, i), 0); + }; + const front: rt.usize = rt.u8Rem(at(0), 4) as rt.usize; + const b: rt.u8 = rt.u8Rem(at(1), 64); + const _16: rt.Iter = rt.iterMap(rt.iterTake(rt.iterSkip(rt.iterSlice(rt.byteSliceView(data)), 2), rt.u8Rem(at(2), 4) as rt.usize), (_2: rt.u8): rt.u8 => { + return rt.u8Rem(_2, 64); + }); + const small: rt.BTreeSet = rt.btreeExtendKeys(rt.btreeNew(rt.cmp) as rt.BTreeSet, _16, true, undefined, undefined, 1, true); + const _27: rt.Iter = rt.iterMap(new rt.Range(0, rt.usizeMul(rt.u8Rem(at(3), 3) as rt.usize, 24)), (i2: rt.usize): rt.u8 => { + return rt.u8Rem(rt.u8WrappingMul(i2 & 0xff, at(4) | 1), 64); + }); + const large: rt.BTreeSet = rt.btreeExtendKeys(rt.btreeNew(rt.cmp) as rt.BTreeSet, _27, true, undefined, undefined, 1, true); + const _40: Uint8Array = Uint8Array.of(b, rt.u8Add(b, 1), rt.u8Add(b, 2)); + const low: rt.BTreeSet = rt.btreeExtendKeys(rt.btreeNew(rt.cmp) as rt.BTreeSet, rt.iterSlice(_40), true, undefined, undefined, 1, true); + const _46: Uint8Array = Uint8Array.of(rt.u8Add(b, 2), rt.u8Add(b, 70)); + const high: rt.BTreeSet = rt.btreeExtendKeys(rt.btreeNew(rt.cmp) as rt.BTreeSet, rt.iterSlice(_46), true, undefined, undefined, 1, true); + const iter: rt.Iter<[rt.BTreeSet, rt.BTreeSet]> = rt.iterSlice([[small, large] as [rt.BTreeSet, rt.BTreeSet], [large, small] as [rt.BTreeSet, rt.BTreeSet], [small, small] as [rt.BTreeSet, rt.BTreeSet], [low, high] as [rt.BTreeSet, rt.BTreeSet], [high, low] as [rt.BTreeSet, rt.BTreeSet]]); + while (true) { + const _69: [rt.BTreeSet, rt.BTreeSet] | rt.Done = iter.next(); + if (_69 === rt.DONE) { + break; + } + const part = fronts$sets_collections_btree_set_Difference_u8(rt.btreeDifference(_69[0], _69[1]), front); + const args2: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtBTreeSetOp(part, f, rt.u8Debug, "Difference")]; + put(out, rt.fmtFormat([args2[0], "|", rt.fmtSpec({ alternate: true }, args2[0])])); + const part2 = fronts$sets_collections_btree_set_Intersection_u8(rt.btreeIntersection(_69[0], _69[1]), front); + const args4: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtBTreeSetOp(part2, f, rt.u8Debug, "Intersection")]; + put(out, rt.fmtFormat([args4[0], "|", rt.fmtSpec({ alternate: true }, args4[0])])); + const part3 = fronts$sets_collections_btree_set_Union_u8(rt.btreeUnion(_69[0], _69[1]), front); + const args6: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtBTreeSetOp(part3, f, rt.u8Debug, "Union")]; + put(out, rt.fmtFormat([args6[0], "|", rt.fmtSpec({ alternate: true }, args6[0])])); + const part4 = fronts$sets_collections_btree_set_SymmetricDifference_u8(rt.btreeSymmetricDifference(_69[0], _69[1]), front); + const args8: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtBTreeSetOp(part4, f, rt.u8Debug, "SymmetricDifference")]; + put(out, rt.fmtFormat([args8[0], "|", rt.fmtSpec({ alternate: true }, args8[0])])); + } + const _131: rt.Iter<[rt.u8, rt.char]> = rt.iterMap(rt.iterTake(rt.iterSlice(rt.byteSliceView(data)), 3), (_23: rt.u8): [rt.u8, rt.char] => { + return [rt.u8Rem(_23, 4), 112] as [rt.u8, rt.char]; + }); + const pairs: rt.BTreeSet<[rt.u8, rt.char]> = rt.btreeExtendKeys(rt.btreeNew(rt.cmpTuple<[rt.u8, rt.char], rt.Ordering>([rt.cmp, rt.cmp])) as rt.BTreeSet<[rt.u8, rt.char]>, _131, true, undefined, undefined, 8, true); + const _135: rt.Iter<[rt.u8, rt.char]> = rt.iterMap(rt.iterTake(rt.iterSkip(rt.iterSlice(rt.byteSliceView(data)), 1), 3), (_26: rt.u8): [rt.u8, rt.char] => { + return [rt.u8Rem(_26, 4), 113] as [rt.u8, rt.char]; + }); + const more: rt.BTreeSet<[rt.u8, rt.char]> = rt.btreeExtendKeys(rt.btreeNew(rt.cmpTuple<[rt.u8, rt.char], rt.Ordering>([rt.cmp, rt.cmp])) as rt.BTreeSet<[rt.u8, rt.char]>, _135, true, undefined, undefined, 8, true); + const part5 = fronts$sets_collections_btree_set_Union_tuple2_u8_char(rt.btreeUnion(pairs, more), front); + const args10: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtBTreeSetOp(part5, f, (value: [rt.u8, rt.char], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.fmtCharDebug(value[1], f)], f), "Union")]; + put(out, rt.fmtFormat([args10[0], "|", rt.fmtSpec({ debugHex: "x" }, args10[0])])); + const part6 = fronts$sets_collections_btree_set_Difference_tuple2_u8_char(rt.btreeDifference(pairs, more), front); + const args12: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtBTreeSetOp(part6, f, (value: [rt.u8, rt.char], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.u8Debug(value[0], f), (f: rt.Formatter) => rt.fmtCharDebug(value[1], f)], f), "Difference")]; + put(out, rt.fmtFormat([rt.fmtSpec({ alternate: true }, args12[0])])); + const _172: rt.Iter = rt.iterTake(rt.iterSlice(rt.byteSliceView(data)), 6); + const it7: rt.Iter = fronts$sets_collections_linked_list_ExtractIf_u8_fmt_sets_closure5(rt.listExtractIfMut(rt.listExtend(rt.listNew() as rt.LinkedList, _172), (x4: rt.Place): boolean => { + return rt.u8Rem(x4.v, 2) === 0; + }), front); + const args14: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtListExtractIf(it7, f, rt.u8Debug)]; + put(out, rt.fmtFormat([args14[0], "|", rt.fmtSpec({ alternate: true }, args14[0]), "|", rt.fmtSpec({ debugHex: "x" }, args14[0])])); + const _192: rt.Iter = rt.iterMap(rt.iterTake(rt.iterSlice(rt.byteSliceView(data)), 3), (_210: rt.u8): Pair.Pair => { + return { _0: _210, _1: 2 }; + }); + const it8: rt.Iter = fronts$sets_collections_linked_list_ExtractIf_fmt_Pair_fmt_sets_closure7(rt.listExtractIf(rt.listExtend(rt.listNew() as rt.LinkedList, _192), (p: Pair.Pair): boolean => { + return rt.u8Rem(p._0, 3) === 0; + }), front); + const args16: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtListExtractIf(it8, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f))]; + put(out, rt.fmtFormat([args16[0]])); + const _212: rt.Iter<[rt.u8, rt.u8]> = rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_211: rt.u8): [rt.u8, rt.u8] => { + const x6: rt.u8 = _211; + return [x6, x6] as [rt.u8, rt.u8]; + }); + const map: rt.HashMap = rt.hashExtend(rt.hashNew() as rt.HashMap, _212, undefined, undefined, undefined, 469762048); + const _215: rt.Iter = rt.iterSlice(rt.byteSliceView(data)); + const set: rt.HashSet = rt.hashExtendKeys(rt.hashNew() as rt.HashSet, _215, undefined, undefined, 469762048); + rt.hashExtractIfMut(map, (k: rt.u8, _310: rt.Place): boolean => { + return k > 9; + }); + rt.hashExtractKeysIf(set, (k2: rt.u8): boolean => { + return k2 > 9; + }); + const args18: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtWriteStr(f, "ExtractIf { .. }"), (f: rt.Formatter) => rt.fmtWriteStr(f, "ExtractIf { .. }")]; + put(out, rt.fmtFormat([args18[0], "|", rt.fmtSpec({ alternate: true }, args18[1])])); +} + +export function fronts$sets_collections_btree_set_Difference_tuple2_u8_char(it: rt.Iter<[rt.u8, rt.char]>, front: rt.usize): rt.Iter<[rt.u8, rt.char]> { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (true) { + if (!(iterStart++ < iterEnd)) { + return it; + } + rt.iterToOption(it.next()); + } +} + +export function fronts$sets_collections_btree_set_Difference_u8(it: rt.Iter, front: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (true) { + if (!(iterStart++ < iterEnd)) { + return it; + } + rt.iterToOption(it.next()); + } +} + +export function fronts$sets_collections_btree_set_Intersection_u8(it: rt.Iter, front: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (true) { + if (!(iterStart++ < iterEnd)) { + return it; + } + rt.iterToOption(it.next()); + } +} + +export function fronts$sets_collections_btree_set_SymmetricDifference_u8(it: rt.Iter, front: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (true) { + if (!(iterStart++ < iterEnd)) { + return it; + } + rt.iterToOption(it.next()); + } +} + +export function fronts$sets_collections_btree_set_Union_tuple2_u8_char(it: rt.Iter<[rt.u8, rt.char]>, front: rt.usize): rt.Iter<[rt.u8, rt.char]> { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (true) { + if (!(iterStart++ < iterEnd)) { + return it; + } + rt.iterToOption(it.next()); + } +} + +export function fronts$sets_collections_btree_set_Union_u8(it: rt.Iter, front: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (true) { + if (!(iterStart++ < iterEnd)) { + return it; + } + rt.iterToOption(it.next()); + } +} + +export function fronts$sets_collections_linked_list_ExtractIf_fmt_Pair_fmt_sets_closure7(it: rt.Iter, front: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (true) { + if (!(iterStart++ < iterEnd)) { + return it; + } + rt.iterToOption(it.next()); + } +} + +export function fronts$sets_collections_linked_list_ExtractIf_u8_fmt_sets_closure5(it: rt.Iter, front: rt.usize): rt.Iter { + let iterStart: rt.usize = 0; + const iterEnd: rt.usize = front; + while (true) { + if (!(iterStart++ < iterEnd)) { + return it; + } + rt.iterToOption(it.next()); + } +} + //# sourceMappingURL=fmt.ts.map diff --git a/ts/fixtures/lang/shapes/expected/lib.ts b/ts/fixtures/lang/shapes/expected/lib.ts index c40bedd09..344a23ce0 100644 --- a/ts/fixtures/lang/shapes/expected/lib.ts +++ b/ts/fixtures/lang/shapes/expected/lib.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rt from "./rt.ts"; -import { ints, strings, derived, written, counts, rounding, panics, wrapped, collections, enums, iters, adaptors, writes, objects, sources } from "./fmt.ts"; +import { ints, strings, derived, written, counts, rounding, panics, wrapped, collections, enums, iters, adaptors, writes, objects, sources, sets } from "./fmt.ts"; import { methods, runs } from "./generics.ts"; import type * as Either from "./generics.Either.ts"; import * as Fixed from "./generics.Fixed.ts"; @@ -202,6 +202,8 @@ export function cases(): [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) adaptors(data22, out23); }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["fmt::sources", (_233: rt.u8, data23: rt.ByteSlice, out24: rt.ByteVec): undefined => { sources(data23, out24); + }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["fmt::sets", (_234: rt.u8, data24: rt.ByteSlice, out25: rt.ByteVec): undefined => { + sets(data24, out25); }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]]; } diff --git a/ts/fixtures/lang/shapes/src/fmt.rs b/ts/fixtures/lang/shapes/src/fmt.rs index 4d531fa25..f20961d84 100644 --- a/ts/fixtures/lang/shapes/src/fmt.rs +++ b/ts/fixtures/lang/shapes/src/fmt.rs @@ -6,7 +6,7 @@ #![allow(dead_code, reason = "fields only `Debug` reads")] use std::cell::{Cell, RefCell}; -use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; use std::fmt::{self, Debug, Display}; use std::ops::{Range, RangeToInclusive}; use std::rc::Rc; @@ -1576,6 +1576,23 @@ pub fn sources(data: &[u8], out: &mut Vec) { let it = std::iter::once(b).chain([at(3), at(4)]).map(|x| x / 2); put(out, &format!("{it:?}|{it:#?}")); + // What a `Repeat` and a `RepeatN` hold, and whether a `OnceWith` still holds its + // closure, which std writes unpadded. + let it = std::iter::repeat(b); + put(out, &format!("{it:?}|{it:#?}|{it:x?}")); + put( + out, + &format!("{:?}", ends(std::iter::repeat(Pair(b, 7)).take(3), front, back)), + ); + let n = usize::from(at(3) % 4); + let it = ends(std::iter::repeat_n(b, n), front, back); + put(out, &format!("{it:?}|{it:#?}")); + let mut it = std::iter::repeat_n(Pair(b, 8), n); + it.nth(usize::from(at(4) % 4)); + put(out, &format!("{it:?}|{it:#?}")); + let it = ends(std::iter::once_with(|| b), front % 2, back % 2); + put(out, &format!("{it:?}|{it:#?}|{it:>20?}")); + // The bytes before the front, and the chars left. let text: String = bytes .iter() @@ -1673,3 +1690,68 @@ pub fn sources(data: &[u8], out: &mut Vec) { ), ); } + +/// A `BTreeSet`'s set operations' `Debug`, each the way std picked to make it and what that +/// reads: merged, each key of the smaller looked up in a set 16 times its size, or answered +/// by where the sets meet, fresh and part read, plain and pretty. And each `ExtractIf`'s: a +/// list's the item it reads next, a hash map's and set's nothing. +pub fn sets(data: &[u8], out: &mut Vec) { + let at = |i: usize| data.get(i).copied().unwrap_or(0); + let front = usize::from(at(0) % 4); + fn fronts(mut it: I, front: usize) -> I { + for _ in 0..front { + it.next(); + } + it + } + let b = at(1) % 64; + let small: BTreeSet = data + .iter() + .skip(2) + .take(usize::from(at(2) % 4)) + .map(|&x| x % 64) + .collect(); + let large: BTreeSet = (0..usize::from(at(3) % 3) * 24) + .map(|i| (i as u8).wrapping_mul(at(4) | 1) % 64) + .collect(); + // Sets where one's least key is the other's greatest. + let low: BTreeSet = [b, b + 1, b + 2].into(); + let high: BTreeSet = [b + 2, b + 70].into(); + for (x, y) in [ + (&small, &large), + (&large, &small), + (&small, &small), + (&low, &high), + (&high, &low), + ] { + let it = fronts(x.difference(y), front); + put(out, &format!("{it:?}|{it:#?}")); + let it = fronts(x.intersection(y), front); + put(out, &format!("{it:?}|{it:#?}")); + let it = fronts(x.union(y), front); + put(out, &format!("{it:?}|{it:#?}")); + let it = fronts(x.symmetric_difference(y), front); + put(out, &format!("{it:?}|{it:#?}")); + } + let pairs: BTreeSet<(u8, char)> = data.iter().take(3).map(|&x| (x % 4, 'p')).collect(); + let more: BTreeSet<(u8, char)> = data.iter().skip(1).take(3).map(|&x| (x % 4, 'q')).collect(); + let it = fronts(pairs.union(&more), front); + put(out, &format!("{it:?}|{it:x?}")); + let it = fronts(pairs.difference(&more), front); + put(out, &format!("{it:#?}")); + + let mut list: LinkedList = data.iter().take(6).copied().collect(); + let it = fronts(list.extract_if(|x| *x % 2 == 0), front); + put(out, &format!("{it:?}|{it:#?}|{it:x?}")); + drop(it); + let mut pairs: LinkedList = data.iter().take(3).map(|&x| Pair(x, 2)).collect(); + let it = fronts(pairs.extract_if(|p| p.0 % 3 == 0), front); + put(out, &format!("{it:?}")); + drop(it); + let mut map: HashMap = data.iter().map(|&x| (x, x)).collect(); + let mut set: HashSet = data.iter().copied().collect(); + put( + out, + &format!("{:?}|{:#?}", map.extract_if(|k, _| *k > 9), set.extract_if(|k| *k > 9)), + ); +} diff --git a/ts/fixtures/lang/shapes/src/lib.rs b/ts/fixtures/lang/shapes/src/lib.rs index abf30f0a8..3878db90f 100644 --- a/ts/fixtures/lang/shapes/src/lib.rs +++ b/ts/fixtures/lang/shapes/src/lib.rs @@ -51,5 +51,6 @@ fn cases() -> Vec<(&'static str, Case)> { ("shapes::uninhabited", |_, data, out| shapes::uninhabited(data, out)), ("fmt::adaptors", |_, data, out| fmt::adaptors(data, out)), ("fmt::sources", |_, data, out| fmt::sources(data, out)), + ("fmt::sets", |_, data, out| fmt::sets(data, out)), ] } diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index c0ded95f1..81d527c46 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -30,6 +30,7 @@ fixtures/reject/src/config.rs:generic+0:51: unsupported type `f16` fixtures/reject/src/config.rs:generic+2:2: a cast from `u64` to `f16` fixtures/reject/src/fmt.rs:chunks_address+1:2: `Debug` of a `ChunksMut`, whose slice std writes as an address, which JS has no counterpart of fixtures/reject/src/fmt.rs:pointer+1:2: `Pointer` formatting, as in `{:p}`, is not supported +fixtures/reject/src/fmt.rs:split_state+1:2: `Debug` of a `str::Split`, whose searcher std writes with its state in UTF-8 bytes, which the runtime does not keep yet fixtures/reject/src/fmt.rs:written+2:10: `fmt::Arguments` with a placeholder, or not made in place, written to `fmt::Sink`'s own `fmt::Write`, which is not supported yet: std splits what a placeholder writes into `write_str` calls the runtime does not make fixtures/reject/src/futures.rs:generic_pending+1:2: `futures::Waiting>` is not supported: its field `poll` is `Poll`, typed `rt.Poll`, whose `Pending` would be `rt.OuterPending` as `Poll>` fixtures/reject/src/futures.rs:nested_poll+0:20: `Poll>>>` is not supported: its `Pending` and `Ready` would both be `rt.OuterPending` diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 7aeecfa46..d3d67ca5a 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -33,6 +33,7 @@ fixtures/reject/src/config.rs:Meters+0:1: a printable type must implement `Displ fixtures/reject/src/config.rs:generic+0:1: a root must not be generic fixtures/reject/src/fmt.rs:chunks_address+1:11: `Debug` of a `ChunksMut`, whose slice std writes as an address, which JS has no counterpart of fixtures/reject/src/fmt.rs:pointer+1:11: `Pointer` formatting, as in `{:p}`, is not supported +fixtures/reject/src/fmt.rs:split_state+1:11: `Debug` of a `str::Split`, whose searcher std writes with its state in UTF-8 bytes, which the runtime does not keep yet fixtures/reject/src/fmt.rs:written+2:10: `fmt::Arguments` with a placeholder, or not made in place, written to `fmt::Sink`'s own `fmt::Write`, which is not supported yet: std splits what a placeholder writes into `write_str` calls the runtime does not make fixtures/reject/src/futures.rs:generic_pending+1:2: `futures::Waiting>` is not supported: its field `poll` is `Poll`, typed `rt.Poll`, whose `Pending` would be `rt.OuterPending` as `Poll>` fixtures/reject/src/futures.rs:nested_poll+0:20: `Poll>>>` is not supported: its `Pending` and `Ready` would both be `rt.OuterPending` diff --git a/ts/fixtures/reject/src/fmt.rs b/ts/fixtures/reject/src/fmt.rs index 97fd2abce..2a424cade 100644 --- a/ts/fixtures/reject/src/fmt.rs +++ b/ts/fixtures/reject/src/fmt.rs @@ -10,6 +10,11 @@ pub fn chunks_address(v: &mut [u8]) -> String { format!("{:?}", v.chunks_mut(2)) } +/// `Debug` of a `str` search, which writes its searcher's state in UTF-8 bytes. +pub fn split_state(s: &str) -> String { + format!("{:?}", s.split(',')) +} + /// A placeholder written to the crate's own `fmt::Write`, which sees each call std makes. pub fn written(w: &mut Sink, n: u8) { use std::fmt::Write; diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index 6ebfea8f6..cf09f96f4 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -23,6 +23,7 @@ roots = [ "config::generic", "fmt::chunks_address", "fmt::pointer", + "fmt::split_state", "fmt::written", "futures::generic_pending", "futures::nested_poll", diff --git a/ts/runtime/rt/collections.ts b/ts/runtime/rt/collections.ts index 708f4b141..a8e9a5f0b 100644 --- a/ts/runtime/rt/collections.ts +++ b/ts/runtime/rt/collections.ts @@ -15,7 +15,7 @@ // A function that may drop a key, value, or item std's would, rather than return or keep // it, takes what drops each that does, as `k`, `v`, or `f`, and drops it where std's does. -import { ByteSlice, ByteVec, byteVecPush, byteVecReserve, type Capped, capHold, capOf, capReserve, capReserveExact, capSet, type CloneFrom, type Debug, Err, type FmtResult, type Formatter, fmtDebugTupleFields, fmtList, type None, Ok, type Place, panic, type RangeBound, type Result, rangeCheck, sliceSort, sliceView, vecCloneFrom, vecExact, vecMax, vecReserve, vecWithCapacity } from "../rt.ts"; +import { ByteSlice, ByteVec, byteVecPush, byteVecReserve, type Capped, capHold, capOf, capReserve, capReserveExact, capSet, type CloneFrom, type Debug, debugStructField, debugStructFinishNonExhaustive, Err, type Fmt, type FmtResult, type Formatter, fmtDebugStruct, fmtDebugStructFields, fmtDebugTupleFields, fmtIter, fmtList, fmtSet, type None, Ok, type Place, panic, type RangeBound, type Result, rangeCheck, sliceSort, sliceView, vecCloneFrom, vecExact, vecMax, vecReserve, vecWithCapacity } from "../rt.ts"; import type { Hashing } from "./hash.ts"; import { type Limbs, lt, type u64, type usize } from "./int.ts"; import { @@ -792,6 +792,94 @@ function retainHash(m: HashMap, f: (key: K, value: V | Place) => } } +/** + * `extract_if`: each entry `f` returns true for, taken out as it is read, in `hashIter`'s + * order, as `[key, value]`, or of a set its key. `f` is given each key and value or, with + * `places`, the value's place, and drops with the iterator; what it has not read stays. + */ +class HashExtractIf extends Iter implements Disposable { + private readonly m: HashMap; + private readonly p: Iterator<[K, V]>; + private readonly o: Iterator<[number, Slot]> | undefined; + /** The chain it reads, by its hash, the slot it reads next, and the last it kept there. */ + private hash = 0; + private at: Slot | undefined; + private kept: Slot | undefined; + private readonly f: (key: K, value: V | Place) => boolean; + private readonly places: boolean; + private readonly keys: boolean; + /** How many it has left to read. */ + private left: number; + + constructor(m: HashMap, f: (key: K, value: V | Place) => boolean, places: boolean, keys: boolean) { + super(); + hold(m); + this.m = m; + this.p = m.p.entries(); + this.o = m.o?.entries(); + this.f = f; + this.places = places; + this.keys = keys; + this.left = hashLen(m); + } + + next(): T | Done { + const m = this.m; + for (; this.left > 0; this.left--) { + const entry = this.p.next(); + if (!entry.done) { + const [key, value] = entry.value; + if (!this.f(key, this.places ? new AtKey(m.p, key) : value)) continue; + const now = this.places ? (m.p.get(key) as V) : value; + m.p.delete(key); + this.left--; + return (this.keys ? key : [key, now]) as T; + } + if (this.at === undefined) { + [this.hash, this.at] = (this.o as Iterator<[number, Slot]>).next().value as [number, Slot]; + this.kept = undefined; + } + const s = this.at; + this.at = s.next; + if (!this.f(s.k, this.places ? s : s.v)) { + this.kept = s; + continue; + } + const o = m.o as Map>; + if (this.kept !== undefined) this.kept.next = s.next; + else if (s.next !== undefined) o.set(this.hash, s.next); + else o.delete(this.hash); + m.n--; + this.left--; + return (this.keys ? s.k : [s.k, s.v]) as T; + } + return DONE; + } + + override sizeHint(): SizeHint { + return [0, this.left]; + } + + [Symbol.dispose](): void { + dispose(this.f); + } +} + +/** `extract_if` of a map, handing `f` each key and value. */ +export function hashExtractIf(m: HashMap, f: (key: K, value: V) => boolean): Iter<[K, V]> { + return new HashExtractIf(m, f as (key: K, value: V | Place) => boolean, false, false); +} + +/** `extract_if` of a map of values JS copies: `f` takes the place of each. */ +export function hashExtractIfMut(m: HashMap, f: (key: K, value: Place) => boolean): Iter<[K, V]> { + return new HashExtractIf(m, f as (key: K, value: V | Place) => boolean, true, false); +} + +/** `extract_if` of a set, handing `f` each key. */ +export function hashExtractKeysIf(m: HashSet, f: (key: K) => boolean): Iter { + return new HashExtractIf(m, f as (key: K) => boolean, false, true); +} + /** * What a collection's iterator yields: its entries as `[key, value]`, keys, values, * `[key, place]`, the place of a value JS copies, or that place alone. @@ -2205,12 +2293,12 @@ function ends(m: BTreeSet): [K, K] { * the greater of two that differ. */ abstract class Merge extends Iter { - private readonly a: Iter; - private readonly b: Iter; + readonly a: Iter; + readonly b: Iter; private readonly c: (a: K, b: K) => Ordering; /** The key held back, and whether it is `a`'s. */ - private held: K | Done = DONE; - private heldA = false; + held: K | Done = DONE; + heldA = false; constructor(a: Iter, b: Iter, c: (a: K, b: K) => Ordering) { super(); @@ -2286,29 +2374,57 @@ export function btreeSymmetricDifference(a: BTreeSet, b: BTreeSet): Ite } /** - * Each key of `a` that the other set lacks: looked up in it, or with no set to look in, - * found by stepping through its keys by `b`, peeked a key ahead. + * A set operation that looks each key of `small` up in `large`: an intersection's, yielding + * those `large` holds if `holds`, or a difference's, those it lacks. */ +class Search extends Iter { + readonly small: Iter; + readonly large: BTreeSet; + private readonly holds: boolean; + + constructor(small: Iter, large: BTreeSet, holds: boolean) { + super(); + this.small = small; + this.large = large; + this.holds = holds; + } + + override clone(): Iter { + return new Search(this.small.clone(), this.large, this.holds); + } + + next(): K | Done { + for (let x = this.small.next(); x !== DONE; x = this.small.next()) { + if (btreeContains(this.large, x) === this.holds) return x; + } + return DONE; + } + + override sizeHint(): SizeHint { + const n = this.small.len(); + return [this.holds ? 0 : Math.max(n - this.large.n, 0), n]; + } +} + +/** Each key of `a` that the other set lacks, found by stepping through its keys by `b`, peeked a key ahead. */ class Difference extends Iter { - private readonly a: Iter; - private readonly set: BTreeSet | undefined; - private readonly b: Iter; + readonly a: Iter; + readonly b: Iter; private readonly c: (a: K, b: K) => Ordering; /** `b`'s next key, once `peeked` says it was read. */ - private peek: K | Done = DONE; - private peeked = false; + peek: K | Done = DONE; + peeked = false; - constructor(a: Iter, set: BTreeSet | undefined, b: Iter, c: (a: K, b: K) => Ordering) { + constructor(a: Iter, b: Iter, c: (a: K, b: K) => Ordering) { super(); this.a = a; - this.set = set; this.b = b; this.c = c; } /** std's: each of its iterators, and the key it peeked. */ override clone(): Iter { - const it = new Difference(this.a.clone(), this.set, this.b.clone(), this.c); + const it = new Difference(this.a.clone(), this.b.clone(), this.c); it.peek = this.peek; it.peeked = this.peeked; return it; @@ -2317,13 +2433,6 @@ class Difference extends Iter { next(): K | Done { let x = this.a.next(); if (x === DONE) return DONE; - if (this.set !== undefined) { - while (btreeContains(this.set, x)) { - x = this.a.next(); - if (x === DONE) return DONE; - } - return x; - } for (;;) { if (!this.peeked) { this.peek = this.b.next(); @@ -2341,7 +2450,7 @@ class Difference extends Iter { override sizeHint(): SizeHint { const n = this.a.len(); - const other = this.set !== undefined ? this.set.n : this.b.len() + (this.peeked && this.peek !== DONE ? 1 : 0); + const other = this.b.len() + (this.peeked && this.peek !== DONE ? 1 : 0); return [Math.max(n - other, 0), n]; } } @@ -2357,15 +2466,15 @@ export function btreeDifference(a: BTreeSet, b: BTreeSet): Iter { if (low > 0 || high < 0) return keys; if (low === 0) keys.next(); else if (high === 0) keys.nextBack(); - else if (a.n <= Math.floor(b.n / TIPPING)) return new Difference(keys, b, iterEmpty(), b.c); - else return new Difference(keys, undefined, btreeKeys(b), b.c); + else if (a.n <= Math.floor(b.n / TIPPING)) return new Search(keys, b, false); + else return new Difference(keys, btreeKeys(b), b.c); return keys; } /** An intersection that merges: each key of `a` that `b` holds. */ class Intersection extends Iter { - private readonly a: Iter; - private readonly b: Iter; + readonly a: Iter; + readonly b: Iter; private readonly c: (a: K, b: K) => Ordering; constructor(a: Iter, b: Iter, c: (a: K, b: K) => Ordering) { @@ -2411,11 +2520,54 @@ export function btreeIntersection(a: BTreeSet, b: BTreeSet): Iter { if (low > 0 || high < 0) return iterEmpty(); if (low === 0) return iterOnce(aMin); if (high === 0) return iterOnce(aMax); - if (a.n <= Math.floor(b.n / TIPPING)) return iterFilter(btreeKeys(a), (key) => btreeContains(b, key)); - if (b.n <= Math.floor(a.n / TIPPING)) return iterFilter(btreeKeys(b), (key) => btreeContains(a, key)); + if (a.n <= Math.floor(b.n / TIPPING)) return new Search(btreeKeys(a), b, true); + if (b.n <= Math.floor(a.n / TIPPING)) return new Search(btreeKeys(b), a, true); return new Intersection(btreeKeys(a), btreeKeys(b), a.c); } +/** + * `Debug` of a `BTreeSet`'s `Difference`, `Intersection`, `Union`, or + * `SymmetricDifference`, `name`, each key by `debug`: the way std picked to make it, by + * the iterators it reads, a set it looks keys up in, and the key it peeked or holds back. + */ +export function fmtBTreeSetOp(it: Iter, f: Formatter, debug: Debug, name: string): FmtResult { + const keys = + (it: Iter): Fmt => + (f) => + fmtIter(it, f, debug, ["Iter"]); + const none: Fmt = (f) => f.out.writeStr("None"); + const some = + (value: Fmt): Fmt => + (f) => + fmtDebugTupleFields(f, "Some", [value]); + const key = + (key: K): Fmt => + (f) => + debug(key, f); + let inner: Fmt; + if (it instanceof Merge) { + const held = it.held as K; + const peeked = it.held === DONE ? none : some((f) => fmtDebugTupleFields(f, it.heldA ? "A" : "B", [key(held)])); + inner = (f) => fmtDebugTupleFields(f, "MergeIterInner", [keys(it.a), keys(it.b), peeked]); + } else if (it instanceof Search) { + const set: Fmt = (f) => fmtSet(btreeKeys(it.large), f, debug); + const names = name === "Difference" ? ["self_iter", "other_iter"] : ["small_iter", "large_set"]; + inner = (f) => fmtDebugStructFields(f, "Search", names, [keys(it.small), set]); + } else if (it instanceof Difference) { + const peeked = !it.peeked ? none : some(it.peek === DONE ? none : some(key(it.peek as K))); + const other: Fmt = (f) => fmtDebugStructFields(f, "Peekable", ["iter", "peeked"], [keys(it.b), peeked]); + inner = (f) => fmtDebugStructFields(f, "Stitch", ["self_iter", "other_iter"], [keys(it.a), other]); + } else if (it instanceof Intersection) { + inner = (f) => fmtDebugStructFields(f, "Stitch", ["a", "b"], [keys(it.a), keys(it.b)]); + } else if (name === "Difference") { + inner = (f) => fmtDebugTupleFields(f, "Iterate", [keys(it)]); + } else { + const left = [...it.remaining()] as K[]; + inner = (f) => fmtDebugTupleFields(f, "Answer", [left.length === 0 ? none : some(key(left[0]))]); + } + return fmtDebugTupleFields(f, name, [inner]); +} + /** `BTreeSet::is_subset`: whether `b` holds each key of `a`. */ export function btreeIsSubset(a: BTreeSet, b: BTreeSet): boolean { if (a.n > b.n) return false; @@ -3821,7 +3973,7 @@ export function listIterMut(l: LinkedList): Iter> { */ class ListExtractIf extends Iter implements Disposable { private readonly l: LinkedList; - private node: ListNode | undefined; + node: ListNode | undefined; private readonly f: (item: T | Place) => boolean; private readonly places: boolean; /** How many it has left to read. */ @@ -3860,6 +4012,13 @@ class ListExtractIf extends Iter implements Disposable { } } +/** `Debug` of a list's `ExtractIf`: the item it reads next, if any. */ +export function fmtListExtractIf(it: Iter, f: Formatter, debug: Debug): FmtResult { + const node = (it as ListExtractIf).node; + const peek: Fmt = (f) => (node === undefined ? f.out.writeStr("None") : fmtDebugTupleFields(f, "Some", [(f) => debug(node.v, f)])); + return debugStructFinishNonExhaustive(debugStructField(fmtDebugStruct(f, "ExtractIf"), "peek", peek)); +} + /** `extract_if`, handing `f` each item. */ export function listExtractIf(l: LinkedList, f: (item: T) => boolean): Iter { return new ListExtractIf(l, f as (item: T | Place) => boolean, false); diff --git a/ts/runtime/rt/iter.ts b/ts/runtime/rt/iter.ts index 62ce34857..4b197b4ba 100644 --- a/ts/runtime/rt/iter.ts +++ b/ts/runtime/rt/iter.ts @@ -593,6 +593,22 @@ export function iterRepeatWith(f: () => T): Iter { return new FromNext(f, (f) => f(), dispose, { hint: () => [USIZE_MAX, undefined] }); } +/** `iter::repeat`: a clone of `element` by `clone` for each item, endlessly; `element` drops by `drop` with it. */ +export function iterRepeat(element: T, clone?: (element: T) => T, drop?: Drop): Iter { + return new RepeatIter(element, clone, drop); +} + +/** `iter::repeat_n`: `n` items of `element`, each a clone by `clone` but the last; `element` drops by `drop` with it, or at once if `n` is 0. */ +export function iterRepeatN(element: T, n: number, clone?: (element: T) => T, drop?: Drop): Iter { + if (n === 0) drop?.(element); + return new RepeatNIter(element, n, clone, drop); +} + +/** `iter::once_with`: what `make` makes, called as it is first read, from either end; it drops uncalled with it. */ +export function iterOnceWith(make: () => T): Iter { + return new OnceWithIter(make); +} + /** * `iter::successors`: `first`, then `succ` of each item, called as that item is yielded. * The item it holds next drops by `drop`, and then `succ`, as std's fields drop. @@ -843,7 +859,7 @@ export function iterSkip(it: Iter, n: number, drop?: Drop): Iter { * reads its iterator by index if it `indexes`, a `TrustedRandomAccess` one. */ export function iterTake(it: Iter, n: number, drop?: Drop, indexes = false): Iter { - return new TakeIter(it, n, drop, indexes); + return it instanceof RepeatIter ? new TakeRepeat(it, n, drop, indexes) : new TakeIter(it, n, drop, indexes); } /** `Iterator::skip_while`, dropping what it skips by `drop`. */ @@ -1134,9 +1150,9 @@ 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; - return iterToOption(last, none); + let final: T | Done = DONE; + for (let item = folded.next(); item !== DONE; item = folded.next()) final = item; + return iterToOption(final, none); } /** `Iterator::nth`, dropping what it skips by `drop`, as its own `nth` does. */ @@ -1760,6 +1776,9 @@ export function ownedEnd(it: Iter, back: boolean, none?: None): T | undefi /** `count`, dropping each item by `drop`, and then `it`, as std's of its kind does. */ function count(it: Iter, drop: Drop | undefined): number { + if (it instanceof RepeatIter) panic("iterator is infinite"); + // std's: its length, and then its element drops with it. + if (it instanceof RepeatNIter) return consumed(it, () => it.left); if (it instanceof FromNext && it.own?.count !== undefined) return it.taken(it.own.count); if (it instanceof EnumerateIter) return count(it.inner, items(drop)); if (it instanceof ChainIter) { @@ -1820,6 +1839,9 @@ function last(it: Iter, drop: Drop | undefined): T | Done { if (it instanceof FromNext && it.own?.last !== undefined) return it.taken(it.own.last); // std's of a box: what it holds, by its own. if (it instanceof Boxed) return last(it.inner, drop); + if (it instanceof RepeatIter) panic("iterator is infinite"); + // std's: its element, uncloned. + if (it instanceof RepeatNIter) return it.left === 0 ? DONE : it.take(); 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. @@ -2337,6 +2359,181 @@ class OptionIter extends Iter implements Disposable { } } +/** `Repeat`, holding `element`, which `clone` clones for each item, and `drop` drops with it. */ +class RepeatIter extends Iter implements Disposable { + readonly element: T; + private readonly copy: ((element: T) => T) | undefined; + private readonly drop: Drop | undefined; + + constructor(element: T, clone?: (element: T) => T, drop?: Drop) { + super(); + this.element = element; + this.copy = clone; + this.drop = drop; + } + + next(): T | Done { + return cloned(this.element, this.copy); + } + + override nextBack(): T | Done { + return this.next(); + } + + /** std's skips nothing, as each item is the same. */ + override advanceBy(): number { + return 0; + } + + override advanceBackBy(): number { + return 0; + } + + override sizeHint(): SizeHint { + return [USIZE_MAX, undefined]; + } + + override clone(): Iter { + return new RepeatIter(cloned(this.element, this.copy), this.copy, this.drop); + } + + [Symbol.dispose](): void { + this.drop?.(this.element); + } +} + +/** + * `RepeatN`, holding `element` while it has items `left`: each a clone by `clone` but the + * last, which is `element` itself. `element` drops by `drop` as an advance passes the last, + * or with it. + */ +class RepeatNIter extends Iter implements Disposable { + element: T | undefined; + left: number; + private readonly copy: ((element: T) => T) | undefined; + private readonly drop: Drop | undefined; + + constructor(element: T, n: number, clone?: (element: T) => T, drop?: Drop) { + super(); + this.element = n === 0 ? undefined : element; + this.left = n; + this.copy = clone; + this.drop = drop; + } + + next(): T | Done { + if (this.left === 0) return DONE; + if (--this.left > 0) return cloned(this.element as T, this.copy); + return this.take(); + } + + override nextBack(): T | Done { + return this.next(); + } + + /** std's: what it has left less `n`, or else none, `element` dropped. */ + override advanceBy(n: number): number { + if (this.left > n) { + this.left -= n; + return 0; + } + const short = n - this.left; + if (this.left > 0) this.dropElement(); + return short; + } + + override advanceBackBy(n: number): number { + return this.advanceBy(n); + } + + override len(): number { + return this.left; + } + + override sizeHint(): SizeHint { + return exactHint(this.left); + } + + override clone(): Iter { + const element = this.left === 0 ? undefined : cloned(this.element as T, this.copy); + return new RepeatNIter(element as T, this.left, this.copy, this.drop); + } + + /** `element`, which it no longer holds. */ + take(): T { + const element = this.element as T; + this.element = undefined; + this.left = 0; + return element; + } + + /** Drop `element`, which it holds. */ + private dropElement(): void { + const element = this.take(); + this.drop?.(element); + } + + [Symbol.dispose](): void { + if (this.left > 0) this.dropElement(); + } +} + +/** `OnceWith`, holding `make` until it is first read, which calls it. */ +class OnceWithIter extends Iter implements Disposable { + make: (() => T) | undefined; + + constructor(make: (() => T) | undefined) { + super(); + this.make = make; + } + + next(): T | Done { + const make = this.make; + if (make === undefined) return DONE; + this.make = undefined; + return make(); + } + + override nextBack(): T | Done { + return this.next(); + } + + override len(): number { + return this.make === undefined ? 0 : 1; + } + + override sizeHint(): SizeHint { + return exactHint(this.len()); + } + + override clone(h?: Clones): Iter { + return new OnceWithIter(this.make === undefined ? undefined : cloned(this.make, h?.f)); + } + + [Symbol.dispose](): void { + const make = this.make; + this.make = undefined; + dispose(make); + } +} + +/** `Debug` of a `Repeat`: its element. */ +export function fmtRepeat(it: Iter, f: Formatter, debug: Debug): FmtResult { + return fmtDebugStructFields(f, "Repeat", ["element"], [(f) => debug((it as RepeatIter).element, f)]); +} + +/** `Debug` of a `RepeatN`: how many it has left, and its element while it holds it. */ +export function fmtRepeatN(it: Iter, f: Formatter, debug: Debug): FmtResult { + const r = it as RepeatNIter; + const element: Fmt = (f) => (r.left === 0 ? f.out.writeStr("None") : fmtDebugTupleFields(f, "Some", [(f) => debug(r.element as T, f)])); + return fmtDebugStructFields(f, "RepeatN", ["count", "element"], [(f) => usizeDebug(r.left, f), element]); +} + +/** `Debug` of a `OnceWith`: whether it holds its closure, which std writes as `_`, unpadded. */ +export function fmtOnceWith(it: Iter, f: Formatter): FmtResult { + return f.out.writeStr((it as OnceWithIter).make === undefined ? "OnceWith(None)" : "OnceWith(Some(_))"); +} + /** * An iterator whose `next` is a function of its source, which `drop` drops, and which `own` * reads by the methods it has of its own. @@ -3562,7 +3759,8 @@ class TakeIter extends Adaptor { } override clone(h?: Clones): Iter { - return new TakeIter(this.inner.clone(h?.i), this.n, this.drop, this.indexes); + const kind = this.constructor as new (inner: Iter, n: number, drop?: Drop, indexes?: boolean) => TakeIter; + return new kind(this.inner.clone(h?.i), this.n, this.drop, this.indexes); } override sizeHint(): SizeHint { @@ -3686,6 +3884,33 @@ class TakeIter extends Adaptor { } } +/** std's `Take` of a `Repeat`, which reads from the back as it does from the front. */ +class TakeRepeat extends TakeIter { + override nextBack(): T | Done { + return this.next(); + } + + override nthBack(n: number, drop?: Drop): T | Done { + return this.nth(n, drop); + } + + override advanceBackBy(n: number, drop?: Drop): number { + return this.advanceBy(n, drop); + } + + override rfold(acc: A, f: (acc: A, item: T) => A, release?: () => void): A { + return this.fold(acc, f, release); + } + + override folded(fold = false): Iter { + const front = super.folded(fold); + return new Folded( + () => front.next(), + () => front.next(), + ); + } +} + class SkipWhileIter extends Calling boolean> { private readonly drop: Drop | undefined; flag = false; diff --git a/ts/src/lower/collections.rs b/ts/src/lower/collections.rs index 284f16b79..0a7216c25 100644 --- a/ts/src/lower/collections.rs +++ b/ts/src/lower/collections.rs @@ -426,7 +426,7 @@ pub fn place_call<'tcx>(b: &Body<'_, '_, 'tcx>, call: &Call<'tcx>) -> bool { ], 0, ), - Std::HashMap => (&["get_mut", "iter_mut", "values_mut", "retain"], 1), + Std::HashMap => (&["get_mut", "iter_mut", "values_mut", "retain", "extract_if"], 1), Std::HashTable => (&["find_mut", "iter_mut", "retain"], 0), Std::TableEntry => (&["get_mut", "into_mut", "and_modify"], 0), Std::BTreeMap => (&["get_mut", "iter_mut", "values_mut", "range_mut", "retain"], 1), @@ -618,6 +618,9 @@ fn hash<'tcx>( (_, "remove_entry") => Expr::rt("hashRemoveEntry", values), (_, "retain") if !set && b.t.needs_place(arg(coll, 1)) => Expr::rt("hashRetainMut", values), (_, "retain") => Expr::rt("hashRetain", values), + (_, "extract_if") if set => Expr::rt("hashExtractKeysIf", values), + (_, "extract_if") if b.t.needs_place(arg(coll, 1)) => Expr::rt("hashExtractIfMut", values), + (_, "extract_if") => Expr::rt("hashExtractIf", values), (_, "iter_mut") if b.t.needs_place(arg(coll, 1)) => Expr::rt("hashIterMut", values), (_, "values_mut") if b.t.needs_place(arg(coll, 1)) => Expr::rt("hashValuesMut", values), (_, "iter" | "iter_mut") if !set => Expr::rt("hashIter", values), diff --git a/ts/src/lower/drop.rs b/ts/src/lower/drop.rs index 2c8f16799..40f005fc1 100644 --- a/ts/src/lower/drop.rs +++ b/ts/src/lower/drop.rs @@ -93,9 +93,14 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { None | Some(Std::Peekable) if self.std_iter(ty) => match adt.has_dtor(tcx) { // What owns its items, an `IntoIter` or a `Drain`, drops those it still holds. true => args.types().any(|t| self.drops(t)), - // A `str` search's holds its pattern inside std's searcher, which no `rt.Iter` - // stands for. - false if super::iter::holds_closure(tcx, adt.did()) => args.types().any(|t| self.drops(t)), + // A `str` search's holds its pattern inside std's searcher, and a `RepeatN` its + // element inside a struct of its own, which no `rt.Iter` stands for. + false + if super::iter::holds_closure(tcx, adt.did()) + || library::std_path(tcx, adt.did()) == ["iter", "sources", "repeat_n", "RepeatN"] => + { + args.types().any(|t| self.drops(t)) + } false => self.fields_drop(*adt, args, true), }, Some(_) => false, diff --git a/ts/src/lower/fmt.rs b/ts/src/lower/fmt.rs index f63e2296e..5bb0b6e38 100644 --- a/ts/src/lower/fmt.rs +++ b/ts/src/lower/fmt.rs @@ -621,13 +621,39 @@ fn iter_debug<'tcx>( let (item, wraps): (Item, &[Wrap]) = match path.as_slice() { ["str", "iter", "Chars"] => return Some(Expr::rt("fmtChars", vec![value.clone(), f.clone()])), ["str", "iter", "CharIndices"] => return Some(call("fmtCharIndices", Vec::new())), + [ + "str", + "iter", + "Split" | "RSplit" | "SplitTerminator" | "RSplitTerminator" | "SplitN" | "RSplitN" | "SplitInclusive" + | "Matches" | "RMatches" | "MatchIndices" | "RMatchIndices" | "Lines" | "LinesAny" | "SplitWhitespace", + ] => { + let name = tcx.item_name(did); + return Some(b.err( + span, + format!( + "`Debug` of a `str::{name}`, whose searcher std writes with its state in UTF-8 bytes, which the runtime does not keep yet" + ), + )); + } ["string", "Drain"] => return Some(call("fmtStringDrain", Vec::new())), ["str", "lossy", "Utf8Chunks"] => return Some(Expr::rt("fmtUtf8Chunks", vec![value.clone(), f.clone()])), // Without its fields, which neither `#` nor a width changes. - ["str", "iter", "EncodeUtf16"] | ["iter", "sources", "repeat_with", "RepeatWith"] => { + ["str", "iter", "EncodeUtf16"] + | ["iter", "sources", "repeat_with", "RepeatWith"] + | ["collections", "hash", "map" | "set", "ExtractIf"] => { return write(format!("{} {{ .. }}", tcx.item_name(did))); } + // The item it reads next. + ["collections", "linked_list", "ExtractIf"] => { + let debug = b.fmt_fn(Trait::Debug, args.types().next()?, span); + return Some(call("fmtListExtractIf", vec![debug])); + } ["iter", "sources", "from_fn", "FromFn"] => return write("FromFn".into()), + ["iter", "sources", "once_with", "OnceWith"] => return Some(call("fmtOnceWith", Vec::new())), + ["iter", "sources", "repeat", "Repeat"] | ["iter", "sources", "repeat_n", "RepeatN"] => { + let debug = b.fmt_fn(Trait::Debug, args.types().next()?, span); + return Some(call(&format!("fmt{}", tcx.item_name(did)), vec![debug])); + } ["iter", "sources", "successors", "Successors"] => { let debug = b.fmt_fn(Trait::Debug, args.types().next()?, span); return Some(call("fmtSuccessors", vec![debug])); @@ -678,6 +704,16 @@ fn iter_debug<'tcx>( let rest = [slice(b)?, Expr::Str(split), taken].into_iter().chain(n); return Some(call("fmtSplit", rest.collect())); } + // The way std picked to make it, and what that reads. + [ + "collections", + "btree", + "set", + name @ ("Difference" | "Intersection" | "SymmetricDifference" | "Union"), + ] => { + let debug = b.fmt_fn(Trait::Debug, args.types().next()?, span); + return Some(call("fmtBTreeSetOp", vec![debug, Expr::Str((*name).into())])); + } // The list of what a clone of it yields. [ "collections", diff --git a/ts/src/lower/iter.rs b/ts/src/lower/iter.rs index aca20c537..e87805d4d 100644 --- a/ts/src/lower/iter.rs +++ b/ts/src/lower/iter.rs @@ -1069,6 +1069,18 @@ pub fn call<'tcx>( return Some(Expr::rt("iterFromFn", [args, none.into_iter().collect()].concat())); } ["iter", "sources", "repeat_with", "repeat_with"] => return Some(Expr::rt("iterRepeatWith", args)), + ["iter", "sources", "once_with", "once_with"] => return Some(Expr::rt("iterOnceWith", args)), + // What clones the element for each item, and drops it. + ["iter", "sources", source @ ("repeat" | "repeat_n"), _] => { + let clone = super::collections::clone_fn(b, targ(0)?, span); + let dropper = b.t.dropper(targ(0)?, span); + let name = if *source == "repeat" { + "iterRepeat" + } else { + "iterRepeatN" + }; + return Some(Expr::rt(name, tail(args, vec![clone, dropper]))); + } // What drops the item it holds next. ["iter", "sources", "successors", "successors"] => { let droppers = [b.t.dropper(targ(0)?, span)].into_iter().chain(b.t.none_arg(targ(0)?)); @@ -1208,17 +1220,22 @@ pub fn call<'tcx>( method(name, tail(rest, vec![clones])) } // `rt.owned`, which drops what `self_ty` holds and its items by `dropper` as - // std's own does, where either drops, or counts a `Cycle` as std's `Take::count` - // does, by its `advance_by`, which stops at a clone that yields nothing where - // `try_fold` reads on: else `rt.iter`, so a bundle that never drops doesn't - // carry it. + // std's own does, where either drops, counts a `Cycle` as std's `Take::count` does, + // by its `advance_by`, which stops at a clone that yields nothing where `try_fold` + // reads on, or reaches a `Repeat`'s or a `RepeatN`'s own, which clone nothing, held + // or yielded to a `Flatten`: else `rt.iter`, so a bundle that never drops + // doesn't carry it. "count" | "last" => { let dropper = b.t.dropper(item, span); let none: Vec = none.into_iter().filter(|_| name == "last").collect(); - let cycles = name == "count" - && (self_ty.walk().filter_map(|arg| arg.as_type())) - .any(|t| std_iter_path(tcx, t).is_some_and(|p| p == ["iter", "adapters", "cycle", "Cycle"])); - match drops_iter(b, self_ty, span) || !undefined(&dropper) || cycles { + let held: Vec> = (held_types(b.t, self_ty).into_iter()) + .filter_map(|t| std_iter_path(tcx, t)) + .collect(); + let cycles = name == "count" && held.iter().any(|p| p == &["iter", "adapters", "cycle", "Cycle"]); + let repeats = held.iter().any(|p| { + p == &["iter", "sources", "repeat", "Repeat"] || p == &["iter", "sources", "repeat_n", "RepeatN"] + }); + match drops_iter(b, self_ty, span) || !undefined(&dropper) || cycles || repeats { true => Some(Expr::rt_of("owned", name).call(tail(vec![recv.clone()], [vec![dropper], none].concat()))), false => method(name, none), } @@ -1595,6 +1612,25 @@ fn array_size<'tcx>(b: &Body<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Expr { } /// The path of the std type `ty` is, if it is one. +/// The types `ty` is made of, and of each iterator among them, those of the iterators it +/// yields, which a `Flatten` reads by their own methods. +fn held_types<'tcx>(t: &Translator<'_, 'tcx>, ty: Ty<'tcx>) -> Vec> { + let mut held: Vec> = Vec::new(); + let mut next = vec![ty]; + while let Some(ty) = next.pop() { + for ty in ty.walk().filter_map(|arg| arg.as_type()) { + if held.contains(&ty) { + continue; + } + held.push(ty); + if let Some(item) = t.iter_item(ty).filter(|&item| t.iter_item(item).is_some()) { + next.push(item); + } + } + } + held +} + fn std_iter_path(tcx: ty::TyCtxt<'_>, ty: Ty<'_>) -> Option> { let ty::Adt(adt, _) = ty.kind() else { return None; @@ -1751,6 +1787,9 @@ fn clones<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, span: Span) -> Option< v if undefined(&v) => parts(vec![("v", Expr::Rt("itself".into()))]), v => parts(vec![("v", v)]), }, + // Those that clone their element by what they were made with. + ["iter", "sources", "repeat", "Repeat"] | ["iter", "sources", "repeat_n", "RepeatN"] => Expr::undefined(), + ["iter", "sources", "once_with", "OnceWith"] => parts(vec![("f", value(b, arg(0)?))]), // Those that own their items, each cloned. ["array", "iter", "IntoIter"] | ["option", "IntoIter"] @@ -1850,8 +1889,10 @@ pub(super) fn holds_closure(tcx: ty::TyCtxt<'_>, did: DefId) -> bool { | ["iter", "adapters", "scan", "Scan"] | ["iter", "sources", "from_fn", "FromFn"] | ["iter", "sources", "repeat_with", "RepeatWith"] + | ["iter", "sources", "once_with", "OnceWith"] | ["iter", "sources", "successors", "Successors"] | ["collections", "linked_list", "ExtractIf"] + | ["collections", "hash", "map" | "set", "ExtractIf"] | [ "str", "iter", diff --git a/ts/src/lower/library.rs b/ts/src/lower/library.rs index f2ea687e3..ff734f269 100644 --- a/ts/src/lower/library.rs +++ b/ts/src/lower/library.rs @@ -1260,14 +1260,16 @@ fn called_closures<'tcx>( let mentions = |t: Ty<'tcx>| t.walk().any(|a| a.as_type() == Some(input)); if mentions(output) { // An `rt.Iter` drops the closure it holds, an `rt.PollFn` one it owns, and an - // `rt.LazyCell` one it never calls, and one it calls through `FnOnce` as it does. + // `rt.LazyCell` or a `OnceWith` one it never calls, and one it calls through + // `FnOnce` as it does. let holder = match output.kind() { ty::Adt(adt, args) if args.types().any(|a| a == input) => Some(adt.did()), _ => None, }; let iter = holder.is_some_and(|did| super::iter::holds_closure(tcx, did)); let holds = holder.and_then(|did| Std::of(tcx, did)); - let lazy = matches!(holds, Some(Std::LazyCell | Std::LazyLock)); + let lazy = matches!(holds, Some(Std::LazyCell | Std::LazyLock)) + || holder.is_some_and(|did| std_path(tcx, did) == ["iter", "sources", "once_with", "OnceWith"]); if lent && iter && i < args.len() { let f = std::mem::replace(&mut args[i], Expr::undefined()); args[i] = Expr::rt("lent", vec![f]);