diff --git a/quest/m3/README.md b/quest/m3/README.md index 44e36f92e..6de820d3f 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -24,7 +24,7 @@ generic std gap is planned here even when moq never calls it. - [Waiting: a slice of one byte behind any &mut](/quest/m3/ts-slice-of-one.md) - `slice::from_mut` and `array::from_mut` of a `&mut u8` translate once a consumer calls them - [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 `Once`, `Repeat`, `FromFn`, an array's `IntoIter`, and std's other iterators writes what std'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 - [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-iter-source-debug.md b/quest/m3/ts-iter-source-debug.md index 645e725b3..781a6bcc0 100644 --- a/quest/m3/ts-iter-source-debug.md +++ b/quest/m3/ts-iter-source-debug.md @@ -1,18 +1,29 @@ -# [S] Debug of std's other iterators +# [M] Debug of std's other iterators ## Goal -[rust2-ts](/ts/README.md) translates `Debug` of std's iterators that still have no -mapping, so an adaptor over one writes what std's does instead of being refused: -iterator sources such as `Once`, `Repeat`, `RepeatN`, `FromFn`, `Successors`, -`OnceWith`, and `RepeatWith`, an array's and an `Option`'s or `Result`'s iterators, and -`str`'s iterators other than `Chars` and `Bytes`. Proven by differential tests against -native Rust. +[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. ## Plan -Found while translating `Debug` of the adaptors: `char::decode_utf16([..])` refuses at -its span, as `Debug` of `array::IntoIter` has no mapping. Read each of std's impls, which -write private fields of their own (`Once { inner: IntoIter { inner: Item { opt } } }`), -and survey which share a shape before choosing how the runtime writes them, as -`iter_debug` and `adaptor_debug` in `src/lower/fmt.rs` do. +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. + +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. diff --git a/ts/README.md b/ts/README.md index c772d916a..94ccf0b30 100644 --- a/ts/README.md +++ b/ts/README.md @@ -296,7 +296,12 @@ 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. `Debug` of `Bound`, `Ordering`, `Reverse`, `AssertUnwindSafe`, and `ControlFlow` is +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 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/shapes/expected/core/bool.ts b/ts/fixtures/lang/shapes/expected/core/bool.ts index c95c295ec..921a05c11 100644 --- a/ts/fixtures/lang/shapes/expected/core/bool.ts +++ b/ts/fixtures/lang/shapes/expected/core/bool.ts @@ -1,6 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rt from "../rt.ts"; +import type * as Pair from "../fmt.Pair.ts"; import type * as Void from "../shapes.Void.ts"; export function thenSome$0ztng9q(self: boolean, t: rt.Result): rt.Result | undefined { @@ -10,6 +11,20 @@ export function thenSome$0ztng9q(self: boolean, t: rt.Result) return t; } +export function thenSome$1ou04rm(self: boolean, t: Pair.Pair): Pair.Pair | undefined { + if (!self) { + return undefined; + } + return t; +} + +export function thenSome$0n2gkz4(self: boolean, t: rt.i32): rt.i32 | undefined { + if (!self) { + return undefined; + } + return t; +} + export function thenSome$0d5am30(self: boolean, t: rt.u8): rt.u8 | undefined { if (!self) { return undefined; diff --git a/ts/fixtures/lang/shapes/expected/core/option.ts b/ts/fixtures/lang/shapes/expected/core/option.ts index 453748371..2a51c3086 100644 --- a/ts/fixtures/lang/shapes/expected/core/option.ts +++ b/ts/fixtures/lang/shapes/expected/core/option.ts @@ -57,6 +57,13 @@ export function map$18z3v8h(self: Dir.Dir | undefined, _: (a0: Dir.Dir) => rt.u8 return from$convert_From_shapes_Dir_u8(self); } +export function map$0phsnvg(self: rt.u8 | undefined, _: (a0: rt.u8) => rt.u8 | undefined): rt.u8 | undefined | rt.None { + if (self === undefined) { + return rt.None; + } + return self; +} + export function mapOr$1a3irjf(self: rt.ByteVec | undefined, default_: rt.u8, f: (a0: rt.ByteVec) => rt.u8): rt.u8 { if (self === undefined) { return default_; @@ -106,6 +113,13 @@ export function okOr$1vxk0yk(self: rt.u8 | undefined, err: rt.u8): rt.Result rt.u8 | undefined | rt.None): rt.u8 | undefined | rt.None { + if (self === undefined) { + return rt.None; + } + return f(self); +} + export function clone$0hmts8n(self: rt.u16[] | undefined): rt.u16[] | undefined { if (self === undefined) { return undefined; diff --git a/ts/fixtures/lang/shapes/expected/fmt.ts b/ts/fixtures/lang/shapes/expected/fmt.ts index 705095988..7be60d648 100644 --- a/ts/fixtures/lang/shapes/expected/fmt.ts +++ b/ts/fixtures/lang/shapes/expected/fmt.ts @@ -2,8 +2,8 @@ import * as rt from "./rt.ts"; import { copy$array_tuple2_u8_u8, copy$array_u8, copy$tuple2_u8_u8 } from "./lib.ts"; -import { thenSome$0d5am30, then$0uwf92a } from "./core/bool.ts"; -import { unwrapOr$0k15iai as option_unwrapOr$0k15iai, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr } from "./core/option.ts"; +import { thenSome$1ou04rm, thenSome$0n2gkz4, thenSome$0d5am30, then$0uwf92a } from "./core/bool.ts"; +import { unwrapOr$0k15iai as option_unwrapOr$0k15iai, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$0phsnvg as option_map$0phsnvg, andThen$1bd14ex as option_andThen$1bd14ex } from "./core/option.ts"; import * as Bare from "./fmt.Bare.ts"; import * as Braced from "./fmt.Braced.ts"; import * as Capped from "./fmt.Capped.ts"; @@ -3364,4 +3364,734 @@ export function objects(data: rt.ByteSlice, out: rt.ByteVec): void { } } +/** + * std's iterator sources', an `Option`'s, a `Result`'s, and an array's iterators', and a + * slice's parts' `Debug`, each the state std's fields keep: fresh, read from either end, + * and past the end, plain and pretty. + */ +export function sources(data: rt.ByteSlice, out: rt.ByteVec): void { + let result!: rt.Result; + let held!: rt.Result; + const at: (a0: rt.usize) => rt.u8 = (i: rt.usize): rt.u8 => { + return option_unwrapOr$0r2bmpr(rt.byteSliceGet(data, i), 0); + }; + const _6: [rt.usize, rt.usize] = [rt.u8Rem(at(0), 4) as rt.usize, rt.u8Rem(at(1), 3) as rt.usize]; + const front: rt.usize = _6[0]; + const back: rt.usize = _6[1]; + const b: rt.u8 = at(2); + const bytes: rt.ByteSlice = rt.byteSliceRange(data, 0, rt.min(data.length, 7)); + const part2 = fronts$sources_iter_Once_u8(rt.iterOnce(b), rt.usizeRem(front, 2)); + const args2: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(part2, f, rt.u8Debug, [["Once", "inner"], ["IntoIter", "inner"], ["Item", "opt"]])]; + put(out, rt.fmtFormat([args2[0], "|", rt.fmtSpec({ alternate: true }, args2[0]), "|", rt.fmtSpec({ debugHex: "x" }, args2[0])])); + const part3 = rt.iterOnce(thenSome$1ou04rm(rt.u8Rem(b, 2) === 0, { _0: b, _1: -1 })); + const args4: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(part3, f, (value: Pair.Pair | undefined, f: rt.Formatter) => rt.fmtOption(value, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f)), [["Once", "inner"], ["IntoIter", "inner"], ["Item", "opt"]])]; + put(out, rt.fmtFormat([args4[0], "|", rt.fmtSpec({ alternate: true }, args4[0])])); + const maybe: rt.u8 | undefined = thenSome$0d5am30(rt.u8Rem(b, 3) !== 0, b); + const _72: rt.Iter = rt.iterOption(maybe); + const _75: rt.Iter = rt.iterOption(maybe); + const args6: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(_72, f, rt.u8Debug, [["Iter", "inner"], ["Item", "opt"]]), (f: rt.Formatter) => rt.fmtIterOption(_75, f, rt.u8Debug, [["IntoIter", "inner"], ["Item", "opt"]])]; + put(out, rt.fmtFormat([args6[0], "|", rt.fmtSpec({ alternate: true }, args6[1])])); + const pair: Pair.Pair | undefined = thenSome$1ou04rm(rt.u8Rem(b, 2) === 0, { _0: b, _1: 2 }); + const part4 = fronts$sources_option_Iter_fmt_Pair(rt.iterOption(pair), rt.usizeRem(front, 2)); + const args8: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(part4, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f), [["Iter", "inner"], ["Item", "opt"]])]; + put(out, rt.fmtFormat([args8[0]])); + const part5 = rt.iterOption(pair); + const args10: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(part5, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f), [["IterMut", "inner"], ["Item", "opt"]])]; + put(out, rt.fmtFormat([args10[0]])); + const part6 = rt.iterOption(pair); + const args12: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(part6, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f), [["IntoIter", "inner"], ["Item", "opt"]])]; + put(out, rt.fmtFormat([args12[0]])); + const _132: Array = [rt.None, undefined, b]; + const _138: rt.usize = rt.u8Rem(b, 3) as rt.usize; + if (!(_138 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _138); + } + const nested: rt.u8 | undefined | rt.None = _132[_138]; + const _150: rt.Iter = rt.iterOption(nested, undefined, rt.None); + const _153: rt.Iter = rt.iterOption(nested, undefined, rt.None); + const args14: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(_150, f, (value: rt.u8 | undefined, f: rt.Formatter) => rt.fmtOption(value, f, rt.u8Debug), [["Iter", "inner"], ["Item", "opt"]]), (f: rt.Formatter) => rt.fmtIterOption(_153, f, (value: rt.u8 | undefined, f: rt.Formatter) => rt.fmtOption(value, f, rt.u8Debug), [["IntoIter", "inner"], ["Item", "opt"]])]; + put(out, rt.fmtFormat([args14[0], "|", rt.fmtSpec({ debugHex: "x" }, args14[1])])); + let mine: rt.u8 | undefined = maybe; + const part7 = fronts$sources_option_IterMut_u8(rt.iterOption(mine === undefined ? undefined : rt.place(() => mine as rt.u8, (value) => mine = value)), rt.usizeRem(front, 2)); + const args16: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(part7, f, (value: rt.Place, f: rt.Formatter) => rt.u8Debug(value.v, f), [["IterMut", "inner"], ["Item", "opt"]])]; + put(out, rt.fmtFormat([args16[0]])); + if (!(rt.u8Rem(b, 2) === 0)) { + result = rt.Err({ _0: b, _1: 3 }); + } else { + result = rt.Ok(b); + } + const _190: rt.Iter = rt.iterResult(result); + const _193: rt.Iter = rt.iterResult(result); + const args18: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(_190, f, rt.u8Debug, [["Iter", "inner"]]), (f: rt.Formatter) => rt.fmtIterOption(_193, f, rt.u8Debug, [["IntoIter", "inner"]])]; + put(out, rt.fmtFormat([args18[0], "|", rt.fmtSpec({ alternate: true }, args18[1])])); + if (!(rt.u8Rem(b, 3) === 0)) { + held = rt.Ok({ _0: b, _1: 4 }); + } else { + held = rt.Err(b); + } + const part8 = fronts$sources_result_IterMut_fmt_Pair(rt.iterResult(held), rt.usizeRem(front, 2)); + const args20: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(part8, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f), [["IterMut", "inner"]])]; + put(out, rt.fmtFormat([args20[0]])); + const part9 = fronts$sources_result_IntoIter_fmt_Pair(rt.iterResult(held), rt.usizeRem(front, 2)); + const args22: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIterOption(part9, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f), [["IntoIter", "inner"]])]; + put(out, rt.fmtFormat([args22[0]])); + const _243: rt.u8 = at(3); + const _246: rt.u8 = at(4); + const _249: rt.u8 = at(5); + const part10 = ends$sources_array_IntoIter_u8_4(rt.iterSlice(Uint8Array.of(b, _243, _246, _249)), front, back); + const args24: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIter(part10, f, rt.u8Debug, ["IntoIter"])]; + put(out, rt.fmtFormat([args24[0], "|", rt.fmtSpec({ alternate: true }, args24[0]), "|", rt.fmtSpec({ zero: true, debugHex: "x", width: 2 }, args24[0])])); + const part11 = ends$sources_array_IntoIter_fmt_Pair_2(rt.iterSlice([{ _0: b, _1: 5 }, { _0: at(3), _1: 6 }]), rt.usizeRem(front, 3), rt.usizeRem(back, 2)); + const args26: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIter(part11, f, (value: Pair.Pair, f: rt.Formatter) => Pair.fmt$fmt_Debug(value, f), ["IntoIter"])]; + put(out, rt.fmtFormat([args26[0], "|", rt.fmtSpec({ alternate: true }, args26[0])])); + const part12 = rt.iterSlice(Uint8Array.of()); + const args28: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtIter(part12, f, rt.u8Debug, ["IntoIter"])]; + put(out, rt.fmtFormat([args28[0]])); + let n: rt.i32 = 0; + const it5: rt.Iter = rt.iterFromFn((): rt.i32 | undefined => { + n = rt.i32Add(n, 1); + return thenSome$0n2gkz4(n < 3, n); + }); + const args30: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtWriteStr(f, "FromFn")]; + put(out, rt.fmtFormat([args30[0], "|", rt.fmtSpec({ alternate: true }, args30[0])])); + const part13 = rt.iterTake(it5, 2); + const args32: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtCounted(part13, f, "Take", (_value: rt.Iter, f: rt.Formatter) => rt.fmtWriteStr(f, "FromFn"))]; + put(out, rt.fmtFormat([args32[0]])); + const it6: rt.Iter = rt.iterRepeatWith((): rt.u8 => { + return b; + }); + const args34: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtWriteStr(f, "RepeatWith { .. }")]; + put(out, rt.fmtFormat([args34[0], "|", rt.fmtSpec({ alternate: true }, args34[0])])); + const part14 = rt.iterSkip(it6, 1); + const args36: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtCounted(part14, f, "Skip", (_value: rt.Iter, f: rt.Formatter) => rt.fmtWriteStr(f, "RepeatWith { .. }"))]; + put(out, rt.fmtFormat([rt.fmtSpec({ alternate: true }, args36[0])])); + const part15 = fronts$sources_iter_Successors_u8_fmt_sources_closure3(rt.iterSuccessors(b, (_22: rt.u8): rt.u8 | undefined => { + return rt.u8CheckedAdd(_22, 100); + }), front); + const args38: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSuccessors(part15, f, rt.u8Debug)]; + put(out, rt.fmtFormat([args38[0], "|", rt.fmtSpec({ alternate: true }, args38[0]), "|", rt.fmtSpec({ debugHex: "x" }, args38[0])])); + const part16 = fronts$sources_iter_Successors_Option_u8_fmt_sources_closure4(rt.iterSuccessors(b as rt.u8 | undefined | rt.None, (_26: rt.u8 | undefined): rt.u8 | undefined | rt.None => { + return option_andThen$1bd14ex(_26, (x3: rt.u8): rt.u8 | undefined | rt.None => { + return option_map$0phsnvg(rt.u8CheckedSub(x3, 100), (a0: rt.u8): rt.u8 | undefined => { + return a0; + }); + }); + }, undefined, rt.None), front); + const args40: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtSuccessors(part16, f, (value: rt.u8 | undefined, f: rt.Formatter) => rt.fmtOption(value, f, rt.u8Debug))]; + put(out, rt.fmtFormat([args40[0]])); + const part17 = rt.iterMap(rt.iterChain(rt.iterOnce(b), rt.iterSlice(Uint8Array.of(at(3), at(4)))), (x4: rt.u8): rt.u8 => { + return rt.u8Div(x4, 2); + }); + 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 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)) { + rt.panic("index out of bounds: the len is " + 5 + " but the index is " + _54); + } + 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])])); + 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 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 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 => { + 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 => { + 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 => { + 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 => { + 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 => { + 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 => { + 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 => { + 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 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 => { + 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 => { + 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 => { + 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 => { + 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 => { + 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 => { + 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]; + 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]])); +} + +export function ends$sources_array_IntoIter_fmt_Pair_2(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_array_IntoIter_u8_4(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; + 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_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_slice_Chunks_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_slice_RChunksExact_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_slice_RChunks_u16(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_RChunks_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_slice_RSplitMut_u8_fmt_sources_closure8(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_RSplit_u8_fmt_sources_closure8(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_SplitInclusiveMut_u8_fmt_sources_closure8(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_SplitInclusive_u8_fmt_sources_closure8(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_SplitMut_u16_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) { + 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_SplitMut_u8_fmt_sources_closure8(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_Split_u16_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) { + 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_Split_u8_fmt_sources_closure8(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_Windows_u16(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_Windows_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_str_CharIndices(it: rt.Iter<[rt.usize, rt.char]>, front: rt.usize, back: rt.usize): rt.Iter<[rt.usize, rt.char]> { + 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_string_Drain(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 fronts$sources_iter_Once_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$sources_iter_Successors_Option_u8_fmt_sources_closure4(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(), rt.None); + } +} + +export function fronts$sources_iter_Successors_u8_fmt_sources_closure3(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$sources_option_IterMut_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$sources_option_Iter_fmt_Pair(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$sources_result_IntoIter_fmt_Pair(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$sources_result_IterMut_fmt_Pair(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$sources_slice_RSplitNMut_u8_fmt_sources_closure8(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$sources_slice_RSplitN_u8_fmt_sources_closure8(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$sources_slice_SplitNMut_u8_fmt_sources_closure8(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$sources_slice_SplitN_u16_fmt_sources_closure9(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$sources_slice_SplitN_u8_fmt_sources_closure8(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$sources_slice_Windows_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()); + } +} + //# sourceMappingURL=fmt.ts.map diff --git a/ts/fixtures/lang/shapes/expected/lib.ts b/ts/fixtures/lang/shapes/expected/lib.ts index 503436f75..c40bedd09 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 } from "./fmt.ts"; +import { ints, strings, derived, written, counts, rounding, panics, wrapped, collections, enums, iters, adaptors, writes, objects, sources } from "./fmt.ts"; import { methods, runs } from "./generics.ts"; import type * as Either from "./generics.Either.ts"; import * as Fixed from "./generics.Fixed.ts"; @@ -200,6 +200,8 @@ export function cases(): [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) uninhabited(data21, out22); }] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["fmt::adaptors", (_232: rt.u8, data22: rt.ByteSlice, out23: rt.ByteVec): undefined => { 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]]; } diff --git a/ts/fixtures/lang/shapes/src/fmt.rs b/ts/fixtures/lang/shapes/src/fmt.rs index 10fe40760..4d531fa25 100644 --- a/ts/fixtures/lang/shapes/src/fmt.rs +++ b/ts/fixtures/lang/shapes/src/fmt.rs @@ -1502,3 +1502,174 @@ pub fn objects(data: &[u8], out: &mut Vec) { drop(boxed); dropped(out); } + +/// std's iterator sources', an `Option`'s, a `Result`'s, and an array's iterators', and a +/// slice's parts' `Debug`, each the state std's fields keep: fresh, read from either end, +/// and past the end, plain and pretty. +pub fn sources(data: &[u8], out: &mut Vec) { + let at = |i: usize| data.get(i).copied().unwrap_or(0); + let (front, back) = (usize::from(at(0) % 4), usize::from(at(1) % 3)); + fn ends(mut it: I, front: usize, back: usize) -> I { + for _ in 0..front { + it.next(); + } + for _ in 0..back { + it.next_back(); + } + it + } + fn fronts(mut it: I, front: usize) -> I { + for _ in 0..front { + it.next(); + } + it + } + let b = at(2); + let bytes = &data[..data.len().min(7)]; + + // What each holds, an `Option`, until it is read. + let it = fronts(std::iter::once(b), front % 2); + put(out, &format!("{it:?}|{it:#?}|{it:x?}")); + let it = std::iter::once((b % 2 == 0).then_some(Pair(b, -1))); + put(out, &format!("{it:?}|{it:#?}")); + let maybe = (b % 3 != 0).then_some(b); + put(out, &format!("{:?}|{:#?}", maybe.iter(), maybe.into_iter())); + let mut pair = (b % 2 == 0).then_some(Pair(b, 2)); + put(out, &format!("{:?}", fronts(pair.iter(), front % 2))); + put(out, &format!("{:?}", pair.iter_mut())); + put(out, &format!("{:?}", pair.into_iter())); + let nested: Option> = [None, Some(None), Some(Some(b))][usize::from(b % 3)]; + put(out, &format!("{:?}|{:x?}", nested.iter(), nested.into_iter())); + let mut mine = maybe; + put(out, &format!("{:?}", fronts(mine.iter_mut(), front % 2))); + let result: Result = if b % 2 == 0 { Ok(b) } else { Err(Pair(b, 3)) }; + put(out, &format!("{:?}|{:#?}", result.iter(), result.clone().into_iter())); + let mut held: Result = if b % 3 == 0 { Err(b) } else { Ok(Pair(b, 4)) }; + put(out, &format!("{:?}", fronts(held.iter_mut(), front % 2))); + put(out, &format!("{:?}", fronts(held.into_iter(), front % 2))); + + // An array's elements it has left. + let it = ends([b, at(3), at(4), at(5)].into_iter(), front, back); + put(out, &format!("{it:?}|{it:#?}|{it:02x?}")); + let it = ends([Pair(b, 5), Pair(at(3), 6)].into_iter(), front % 3, back % 2); + put(out, &format!("{it:?}|{it:#?}")); + put(out, &format!("{:?}", [0u8; 0].into_iter())); + + // Closures std writes none of, and the item a `Successors` yields next. + let mut n = 0; + let it = std::iter::from_fn(|| { + n += 1; + (n < 3).then_some(n) + }); + put(out, &format!("{it:?}|{it:#?}")); + put(out, &format!("{:?}", it.take(2))); + let it = std::iter::repeat_with(|| b); + put(out, &format!("{it:?}|{it:#?}")); + put(out, &format!("{:#?}", it.skip(1))); + let it = fronts(std::iter::successors(Some(b), |&x| x.checked_add(100)), front); + put(out, &format!("{it:?}|{it:#?}|{it:x?}")); + let it = fronts( + std::iter::successors(Some(Some(b)), |&x| x.and_then(|x| x.checked_sub(100).map(Some))), + front, + ); + put(out, &format!("{it:?}")); + let it = std::iter::once(b).chain([at(3), at(4)]).map(|x| x / 2); + put(out, &format!("{it:?}|{it:#?}")); + + // The bytes before the front, and the chars left. + let text: String = bytes + .iter() + .map(|&b| ['a', 'é', '中', '🦀', '\n'][usize::from(b % 5)]) + .collect(); + let it = ends(text.char_indices(), front, back); + put(out, &format!("{it:?}|{it:#?}|{it:x?}")); + let mut drained = text.clone(); + let it = ends(drained.drain(..), front, back); + put(out, &format!("{it:?}|{it:#?}")); + drop(it); + + // A slice's parts: what is left of it, and past its end, as `nth` and `next_back` leave + // a `Windows`. + let size = usize::from(at(3) % 4) + 1; + let it = ends(bytes.windows(size), front, back); + put(out, &format!("{it:?}|{it:#?}|{it:x?}")); + let mut it = bytes.windows(size); + it.nth(usize::from(at(4) % 8)); + put(out, &format!("{it:?}")); + let mut it = fronts(bytes.windows(size), 8); + put(out, &format!("{it:?}")); + it.next_back(); + put(out, &format!("{it:?}")); + let mut it = bytes.windows(size); + it.nth_back(usize::from(at(4) % 8)); + put(out, &format!("{it:?}")); + let wide: Vec = bytes.iter().map(|&b| u16::from(b) * 0x101).collect(); + let it = ends(wide.windows(size), front, back); + put(out, &format!("{it:?}|{it:#x?}")); + let it = ends(bytes.chunks(size), front, back); + put(out, &format!("{it:?}|{it:#?}")); + let it = ends(wide.chunks_exact(size), front, back); + put(out, &format!("{it:?}|{it:#?}")); + let it = ends(bytes.chunks_exact(size), front, back); + put(out, &format!("{it:?}")); + let it = ends(wide.rchunks(size), front, back); + put(out, &format!("{it:?}")); + let it = ends(bytes.rchunks(size), front, back); + put(out, &format!("{it:?}|{it:#?}")); + let it = ends(bytes.rchunks_exact(size), front, back); + put(out, &format!("{it:?}")); + let mut it = wide.rchunks_exact(size); + it.nth(usize::from(at(4) % 4)); + put(out, &format!("{it:?}")); + + // What is left to split, which a `&mut` one gives up as it finishes. + let sep = |x: &u8| x % 3 == 0; + let it = ends(bytes.split(sep), front, back); + put(out, &format!("{it:?}|{it:#?}|{it:x?}")); + let it = ends(bytes.split_inclusive(sep), front, back); + put(out, &format!("{it:?}")); + let it = ends(bytes.rsplit(sep), front, back); + put(out, &format!("{it:?}")); + let it = fronts(bytes.splitn(usize::from(at(4) % 4), sep), front); + put(out, &format!("{it:?}|{it:#?}")); + let it = fronts(bytes.rsplitn(2, sep), front); + put(out, &format!("{it:?}")); + let wide_sep = |x: &u16| x % 3 == 0; + let it = ends(wide.split(wide_sep), front, back); + put(out, &format!("{it:?}")); + let it = fronts(wide.splitn(2, wide_sep), front); + put(out, &format!("{it:?}")); + let mut owned = bytes.to_vec(); + let it = ends(owned.split_mut(sep), front, back); + put(out, &format!("{it:?}|{it:#?}")); + let it = ends(owned.split_inclusive_mut(sep), front, back); + put(out, &format!("{it:?}")); + let it = ends(owned.rsplit_mut(sep), front, back); + put(out, &format!("{it:?}")); + let it = fronts(owned.splitn_mut(2, sep), front); + put(out, &format!("{it:?}")); + let it = fronts(owned.rsplitn_mut(usize::from(at(4) % 4), sep), front); + put(out, &format!("{it:?}")); + let mut owned = wide.clone(); + let it = ends(owned.split_mut(wide_sep), front, back); + put(out, &format!("{it:?}")); + + // A hash set's operations, of at most one key, since std leaves their order unspecified. + let (mut one, mut other) = (HashSet::new(), HashSet::new()); + if b % 2 == 0 { + one.insert(b); + } + if b % 3 == 0 { + other.insert(b); + } + put( + out, + &format!( + "{:?}|{:#?}|{:?}|{:?}", + one.difference(&other), + one.intersection(&other), + one.symmetric_difference(&other), + one.union(&other) + ), + ); +} diff --git a/ts/fixtures/lang/shapes/src/lib.rs b/ts/fixtures/lang/shapes/src/lib.rs index 84efeeb25..abf30f0a8 100644 --- a/ts/fixtures/lang/shapes/src/lib.rs +++ b/ts/fixtures/lang/shapes/src/lib.rs @@ -50,5 +50,6 @@ fn cases() -> Vec<(&'static str, Case)> { ("shapes::flows", |_, data, out| shapes::flows(data, out)), ("shapes::uninhabited", |_, data, out| shapes::uninhabited(data, out)), ("fmt::adaptors", |_, data, out| fmt::adaptors(data, out)), + ("fmt::sources", |_, data, out| fmt::sources(data, out)), ] } diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index 1f0916d8d..d67499483 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -28,6 +28,7 @@ fixtures/reject/src/clones.rs:stashed_slots+5:19: a raw pointer to `(u8, u8)` in fixtures/reject/src/config.rs:Meters+0:1: a printable type must implement `Display` or `Debug` 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: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>` diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index b09fba426..358f21af3 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -31,6 +31,7 @@ fixtures/reject/src/clones.rs:tagged_slots!+2:23: a raw pointer to `(u8, u8)` in fixtures/reject/src/clones.rs:tagged_slots!+2:23: a raw pointer to `(u8, u8)` in `(clones::Dropped, (u8, u8))`, which the crate may put another object in place of fixtures/reject/src/config.rs:Meters+0:1: a printable type must implement `Display` or `Debug` 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: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>` diff --git a/ts/fixtures/reject/src/fmt.rs b/ts/fixtures/reject/src/fmt.rs index 1e8b23741..97fd2abce 100644 --- a/ts/fixtures/reject/src/fmt.rs +++ b/ts/fixtures/reject/src/fmt.rs @@ -5,6 +5,11 @@ pub fn pointer(n: u8) -> String { format!("{:p}", &n) } +/// `Debug` of a `ChunksMut`, which writes its slice's address. +pub fn chunks_address(v: &mut [u8]) -> String { + format!("{:?}", v.chunks_mut(2)) +} + /// 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 0ab9673d6..8d72d2c13 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -21,6 +21,7 @@ roots = [ "clones::stashed_slots", "clones::touched_slots", "config::generic", + "fmt::chunks_address", "fmt::pointer", "fmt::written", "futures::generic_pending", diff --git a/ts/runtime/rt.ts b/ts/runtime/rt.ts index 73e3835df..7ae3b8ffb 100644 --- a/ts/runtime/rt.ts +++ b/ts/runtime/rt.ts @@ -2809,6 +2809,17 @@ export function fmtIter(it: Iter, f: Formatter, debug: Debug, wra return wrapIn(f, wraps, (f) => fmtList(it.remaining() as Iterable, f, debug)); } +/** `Debug` of an `Option`'s, a `Result`'s, or a `Once`'s iterator: the item `it` has left, if any, as an `Option` inside `wraps`, outermost first. */ +export function fmtIterOption(it: Iter, f: Formatter, debug: Debug, wraps: readonly IterWrap[]): FmtResult { + const items = [...it.remaining()] as T[]; + return wrapIn(f, wraps, (f) => (items.length === 0 ? f.out.writeStr("None") : fmtDebugTupleFields(f, "Some", [(f) => debug(items[0], f)]))); +} + +/** `Debug` of what std writes as the list of what a clone of it yields: a `HashSet`'s set operations. */ +export function fmtIterClone(it: Iter, f: Formatter, debug: Debug): FmtResult { + return fmtList(it.clone(), f, debug); +} + /** `Debug` of a `LinkedList`'s `Iter` or `IterMut`, `name`: the list it has left, then its length by `len`. */ export function fmtListIter(it: Iter, f: Formatter, debug: Debug, len: Debug, name: string): FmtResult { const list: Fmt = (f) => fmtList(it.remaining() as Iterable, f, debug); diff --git a/ts/runtime/rt/iter.ts b/ts/runtime/rt/iter.ts index 24c76590e..62ce34857 100644 --- a/ts/runtime/rt/iter.ts +++ b/ts/runtime/rt/iter.ts @@ -1054,6 +1054,38 @@ export function fmtFlatten(it: Iter, f: Formatter, name: string, return fmtDebugStructFields(f, name, ["inner"], [(f) => fmtDebugStructFields(f, "FlattenCompat", ["iter", "frontiter", "backiter"], fields)]); } +/** `Debug` of a `Successors`: the item it yields next, if any. */ +export function fmtSuccessors(it: Iter, f: Formatter, debug: Debug): FmtResult { + const s = it as SuccessorsIter; + const next = (f: Formatter): FmtResult => (s.item === s.none ? f.out.writeStr("None") : fmtDebugTupleFields(f, "Some", [(f) => debug(s.item as T, f)])); + return fmtDebugStructFields(f, "Successors", ["next"], [next]); +} + +/** + * `Debug` of a slice's `Windows`, `Chunks`, `ChunksExact`, `RChunks`, or `RChunksExact`, + * `name`: what its parts left cover by `slice`, an exact one's remainder, and its size. + */ +export function fmtParts(it: Iter, f: Formatter, slice: Debug, name: string): FmtResult { + const p = it as PartsIter; + const [v, size]: Fmt[] = [(f) => slice(p.rest(), f), (f) => usizeDebug(p.size, f)]; + if (name === "Windows") return fmtDebugStructFields(f, name, ["v", "size"], [v, size]); + if (!name.endsWith("Exact")) return fmtDebugStructFields(f, name, ["v", "chunk_size"], [v, size]); + return fmtDebugStructFields(f, name, ["v", "rem", "chunk_size"], [v, (f) => slice(p.remainder(), f), size]); +} + +/** + * `Debug` of a slice's `Split` or one of its forms, `name`: what is left to split by + * `slice`, which a `&mut` one gives up as it finishes if `taken`, and whether it has + * finished; inside its `GenericSplitN` beside its count, under `n`, for a `splitn`. + */ +export function fmtSplit(it: Iter, f: Formatter, slice: Debug, name: string, taken: boolean, n?: string): FmtResult { + const s = it as SplitIter; + const split = (f: Formatter): FmtResult => fmtDebugStructFields(f, name, ["v", "finished"], [(f) => slice(s.rest(taken), f), (f) => fmtBool(s.finished, f)]); + if (n === undefined) return split(f); + const generic = (f: Formatter): FmtResult => fmtDebugStructFields(f, "GenericSplitN", ["iter", "count"], [split, (f) => usizeDebug(s.count as number, f)]); + return fmtDebugStructFields(f, n, ["inner"], [generic]); +} + // Consumers. Each that takes an iterator by value that `drops` takes it as std's does: by // its own `fold` where std's folds, which drops what it holds as it goes, or as `take` // says, and else by `next`, dropping it once done. @@ -2020,7 +2052,7 @@ class SliceMutIter extends Iter> { class PartsIter extends Iter { private readonly s: S; private readonly length: number; - private readonly size: number; + readonly size: number; private readonly step: number; private readonly count: number; /** Whether the first part is at the back of the slice, as `rchunks`' is. */ @@ -2029,6 +2061,8 @@ class PartsIter extends Iter { private front = 0; /** How many parts there are, less those taken from the back. */ private back: number; + /** Whether a read past the end emptied what it has left, as std's `nth` and `next_back` of a `Windows` do. */ + private cleared = false; constructor(s: S, length: number, size: number, step: number, count: number, rev: boolean, part: (s: S, start: number, end: number) => S) { super(); @@ -2055,9 +2089,21 @@ class PartsIter extends Iter { const it = new PartsIter(this.s, this.length, this.size, this.step, this.count, this.rev, this.part); it.front = this.front; it.back = this.back; + it.cleared = this.cleared; return it; } + /** What std's holds of the slice: what the parts it has left cover, or nothing once a read past the end emptied it. */ + rest(): S { + if (this.cleared) return this.part(this.s, 0, 0); + if (this.rev) { + const start = Math.max(this.length - this.back * this.step, 0); + return this.part(this.s, start, Math.max(this.length - this.front * this.step, start)); + } + const end = Math.min(this.back * this.step + this.size - this.step, this.length); + return this.part(this.s, Math.min(this.front * this.step, end), end); + } + /** What the parts leave over, at the end the parts don't start from. */ remainder(): S { const held = this.count * this.size; @@ -2069,7 +2115,19 @@ class PartsIter extends Iter { } override nextBack(): S | Done { - return this.front < this.back ? this.at(--this.back) : DONE; + if (this.front < this.back) return this.at(--this.back); + this.cleared = true; + return DONE; + } + + override nth(n: number): S | Done { + if (n < this.len()) { + this.front += n; + return this.next(); + } + this.front = this.back; + this.cleared = true; + return DONE; } override len(): number { @@ -2086,9 +2144,11 @@ class PartsIter extends Iter { return n - step; } + /** std's reads by `next_back`, so one past the end empties it. */ override advanceBackBy(n: number): number { const step = Math.min(n, this.back - this.front); this.back -= step; + if (step < n) this.cleared = true; return n - step; } } @@ -2168,6 +2228,21 @@ class SplitIter extends Iter implements Disposable { return this.#part(this.#s, this.#start, this.#finished ? this.#start : this.#end); } + /** What std's holds of the slice: what is left to split, which only a `&mut` one gives up as it finishes, if `taken`. */ + rest(taken: boolean): S { + return taken ? this.asSlice() : this.#part(this.#s, this.#start, this.#end); + } + + /** Whether it has yielded its last part. */ + get finished(): boolean { + return this.#finished; + } + + /** How many more parts a `splitn` yields. */ + get count(): number | undefined { + return this.#count; + } + /** The rest, as the last part. */ #finish(): S | Done { if (this.#finished) return DONE; @@ -2243,6 +2318,10 @@ class OptionIter extends Iter implements Disposable { return this.some ? 1 : 0; } + override remaining(): Iterable { + return this.some ? [this.item as T] : []; + } + override clone(h?: Clones): Iter { return new OptionIter(this.some ? cloned(this.item as T, h?.v) : undefined, this.some, this.drop); } @@ -2385,11 +2464,11 @@ class FromNext extends Iter implements Disposable { /** `Successors`, holding the item it yields next, which drops once, as `Calling` does. */ class SuccessorsIter extends Iter implements Disposable { - private item: T | undefined | None; + item: T | undefined | None; private readonly succ: (item: T) => T | undefined | None; private readonly drop: Drop | undefined; /** The `Option`'s `None`. */ - private readonly none: None | undefined; + readonly none: None | undefined; private dropped = false; constructor(first: T | undefined | None, succ: (item: T) => T | undefined | None, drop?: Drop, none?: None) { diff --git a/ts/runtime/rt/str.ts b/ts/runtime/rt/str.ts index 646e9ea39..26e966d13 100644 --- a/ts/runtime/rt/str.ts +++ b/ts/runtime/rt/str.ts @@ -13,7 +13,9 @@ import { type FmtResult, type Formatter, fmtCharDebug, + fmtChars, fmtDebugStructFields, + fmtDebugTupleFields, fmtList, fmtPad, fmtStr, @@ -27,7 +29,7 @@ import { } from "../rt.ts"; import { escapeDebug } from "./char.ts"; import { type Bounds, boundsRange, type Part } from "./collections.ts"; -import { type char, type u8, type u16, type usize, u8Debug } from "./int.ts"; +import { type char, type u8, type u16, type usize, u8Debug, usizeDebug } from "./int.ts"; import { type Clones, DONE, type Done, Iter, iterFilter, iterForEach, iterMap, iterRev, iterSlice, type RangeInclusive, type SizeHint } from "./iter.ts"; import { drop as dispose } from "./task.ts"; @@ -280,45 +282,52 @@ class EncodeUtf16 extends Iter { } } +/** `Debug` of a `CharIndices`: the bytes before its front, and its `Chars`. */ +export function fmtCharIndices(it: Iter, f: Formatter): FmtResult { + const c = it as CharIndices; + return fmtDebugStructFields(f, "CharIndices", ["front_offset", "iter"], [(f) => usizeDebug(c.front as usize, f), (f) => fmtChars(c.chars, f)]); +} + /** `str::char_indices`. */ export function strCharIndices(s: string): Iter<[usize, char]> { return new CharIndices(new Chars(s)); } class CharIndices extends Iter<[usize, char]> { - readonly #chars: Chars; - // The bytes before the front, and before the back once it first moves. - #front = 0; + readonly chars: Chars; + /** The bytes before the front. */ + front = 0; + // The bytes before the back, once it first moves. #back = -1; constructor(chars: Chars) { super(); - this.#chars = chars; + this.chars = chars; } next(): [usize, char] | Done { - const c = this.#chars.next(); + const c = this.chars.next(); if (c === DONE) return DONE; - const at = this.#front; - this.#front += charLen(c); + const at = this.front; + this.front += charLen(c); return [at as usize, c]; } override nextBack(): [usize, char] | Done { - if (this.#back < 0) this.#back = this.#front + stringLen(this.#chars.rest()); - const c = this.#chars.nextBack(); + if (this.#back < 0) this.#back = this.front + stringLen(this.chars.rest()); + const c = this.chars.nextBack(); if (c === DONE) return DONE; this.#back -= charLen(c); return [this.#back as usize, c]; } override sizeHint(): SizeHint { - return this.#chars.sizeHint(); + return this.chars.sizeHint(); } override clone(): Iter<[usize, char]> { - const it = new CharIndices(this.#chars.clone() as Chars); - it.#front = this.#front; + const it = new CharIndices(this.chars.clone() as Chars); + it.front = this.front; it.#back = this.#back; return it; } @@ -1140,6 +1149,11 @@ export function stringDrainAsStr(drain: Iter): string { return (drain as Chars).rest(); } +/** `Debug` of a `String`'s `Drain`: the chars it has yet to yield. */ +export function fmtStringDrain(drain: Iter, f: Formatter): FmtResult { + return fmtDebugTupleFields(f, "Drain", [(f) => fmtStr((drain as Chars).rest(), f)]); +} + class StringDrain extends Chars implements Disposable { readonly #s: Place; readonly #text: string; diff --git a/ts/src/lower/fmt.rs b/ts/src/lower/fmt.rs index 79076d8e3..25a039457 100644 --- a/ts/src/lower/fmt.rs +++ b/ts/src/lower/fmt.rs @@ -552,7 +552,8 @@ pub fn std_impl<'tcx>( /// `Debug` of one of std's iterators that lists the items it has left, as std writes /// them, or `None` for another type. A deque's `Iter` and `IterMut` write the two slices of -/// its ring buffer they have left, and its `Drain` its counts. +/// its ring buffer they have left, and its `Drain` its counts; an `Option`'s iterator the +/// item it has left as an `Option`, and a slice's parts what is left of the slice. fn iter_debug<'tcx>( b: &mut Body<'_, '_, 'tcx>, did: DefId, @@ -562,9 +563,9 @@ fn iter_debug<'tcx>( span: Span, ) -> Option { /// What std writes around the list: a tuple struct's name, or a struct's and its field's. - enum Wrap { - Tuple(&'static str), - Struct(&'static str, &'static str), + enum Wrap<'a> { + Tuple(&'a str), + Struct(&'a str, &'a str), } /// What it lists: a type argument, the map entry of the first two, or a `BTreeSet`'s /// entry of its key and `SetValZST`. @@ -578,16 +579,95 @@ fn iter_debug<'tcx>( let tcx = b.t.tcx; let path = library::std_path(tcx, did); let path: Vec<&str> = path.iter().map(String::as_str).collect(); + let listed = |wraps: &[Wrap]| { + let wraps = (wraps.iter()).map(|wrap| match *wrap { + Tuple(name) => Expr::Str(name.into()), + Struct(name, field) => Expr::Array(vec![Expr::Str(name.into()), Expr::Str(field.into())]), + }); + Expr::Array(wraps.collect()) + }; + let call = |name: &str, rest: Vec| Expr::rt(name, [vec![value.clone(), f.clone()], rest].concat()); + let write = |text: String| Some(Expr::rt("fmtWriteStr", vec![f.clone(), Expr::Str(text)])); + // The item it has left, if any, as std's `Option` inside `wraps`: a reference as it is + // held, a `&mut` to a value JS copies its place. + let option = |b: &mut Body<'_, '_, 'tcx>, wraps: &[Wrap]| { + let item = b.t.iter_item(Ty::new_adt(tcx, tcx.adt_def(did), args))?; + let debug = b.fmt_fn(Trait::Debug, item, span); + Some(call("fmtIterOption", vec![debug, listed(wraps)])) + }; + // What writes a slice of its parts. + let slice = + |b: &mut Body<'_, '_, 'tcx>| Some(b.fmt_fn(Trait::Debug, Ty::new_slice(tcx, args.types().next()?), span)); 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())), + ["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"] => { - return Some(Expr::rt( - "fmtWriteStr", - vec![f.clone(), Expr::Str("EncodeUtf16 { .. }".into())], + ["str", "iter", "EncodeUtf16"] | ["iter", "sources", "repeat_with", "RepeatWith"] => { + return write(format!("{} {{ .. }}", tcx.item_name(did))); + } + ["iter", "sources", "from_fn", "FromFn"] => return write("FromFn".into()), + ["iter", "sources", "successors", "Successors"] => { + let debug = b.fmt_fn(Trait::Debug, args.types().next()?, span); + return Some(call("fmtSuccessors", vec![debug])); + } + ["iter", "sources", "once", "Once"] => { + return option( + b, + &[ + Struct("Once", "inner"), + Struct("IntoIter", "inner"), + Struct("Item", "opt"), + ], + ); + } + ["option", name @ ("Iter" | "IterMut" | "IntoIter")] => { + return option(b, &[Struct(name, "inner"), Struct("Item", "opt")]); + } + ["result", name @ ("Iter" | "IterMut" | "IntoIter")] => return option(b, &[Struct(name, "inner")]), + [ + "slice", + "iter", + name @ ("Windows" | "Chunks" | "ChunksExact" | "RChunks" | "RChunksExact"), + ] => { + let slice = slice(b)?; + return Some(call("fmtParts", vec![slice, Expr::Str((*name).into())])); + } + [ + "slice", + "iter", + "ChunksMut" | "ChunksExactMut" | "RChunksMut" | "RChunksExactMut", + ] => { + let name = tcx.item_name(did); + return Some(b.err( + span, + format!("`Debug` of a `{name}`, whose slice std writes as an address, which JS has no counterpart of"), )); } + // A `splitn`'s is a `GenericSplitN` of the split it is named for. + [ + "slice", + "iter", + name @ ("Split" | "SplitMut" | "SplitInclusive" | "SplitInclusiveMut" | "RSplit" | "RSplitMut" | "SplitN" + | "SplitNMut" | "RSplitN" | "RSplitNMut"), + ] => { + let split = name.replacen('N', "", 1); + let n = (split != *name).then(|| Expr::Str((*name).into())); + let taken = Expr::lit(name.ends_with("Mut").to_string()); + let rest = [slice(b)?, Expr::Str(split), taken].into_iter().chain(n); + return Some(call("fmtSplit", rest.collect())); + } + // The list of what a clone of it yields. + [ + "collections", + "hash", + "set", + "Difference" | "Intersection" | "SymmetricDifference" | "Union", + ] => { + let debug = b.fmt_fn(Trait::Debug, args.types().next()?, span); + return Some(call("fmtIterClone", vec![debug])); + } [ "collections", "vec_deque", @@ -615,6 +695,7 @@ fn iter_debug<'tcx>( | ["collections", "btree", "set", "Iter"] => (Arg(0), &[Tuple("Iter")]), ["slice", "iter", "IterMut"] => (Arg(0), &[Tuple("IterMut")]), ["vec", "into_iter", "IntoIter"] + | ["array", "iter", "IntoIter"] | ["collections", "binary_heap", "IntoIter"] | ["collections", "vec_deque", "into_iter", "IntoIter"] | ["collections", "linked_list", "IntoIter"] => (Arg(0), &[Tuple("IntoIter")]), @@ -646,17 +727,11 @@ fn iter_debug<'tcx>( SetVal => Expr::rt("fmtSetVal", vec![b.fmt_fn(Trait::Debug, arg(0)?, span)]), Byte => b.fmt_fn(Trait::Debug, tcx.types.u8, span), }; - let wraps: Vec = (wraps.iter()) - .map(|wrap| match *wrap { - Tuple(name) => Expr::Str(name.into()), - Struct(name, field) => Expr::Array(vec![Expr::Str(name.into()), Expr::Str(field.into())]), - }) - .collect(); - let mut call = vec![value.clone(), f.clone(), debug]; + let mut rest = vec![debug]; if !wraps.is_empty() { - call.push(Expr::Array(wraps)); + rest.push(listed(wraps)); } - Some(Expr::rt("fmtIter", call)) + Some(call("fmtIter", rest)) } /// `Debug` of one of std's iterator adaptors, as std's derived or written impl writes it: