diff --git a/quest/m3/ts-runtime-throws.md b/quest/m3/ts-runtime-throws.md index d213f6ecd..6f8bd6d3b 100644 --- a/quest/m3/ts-runtime-throws.md +++ b/quest/m3/ts-runtime-throws.md @@ -24,9 +24,8 @@ The rest are gaps. At `main` they include a panic its hook cannot locate ([#556](https://github.com/moq-dev/rust2/pull/556)), a pointer cast to `()` that is not an `Arc`'s or `Rc`'s (`rs.arcErase`, [#562](https://github.com/moq-dev/rust2/pull/562), [#565](https://github.com/moq-dev/rust2/pull/565)), `offset_from` of one Rust allocation -JS keeps in two arrays, a pointer moved past the array JS keeps it in (`AtIndex.reach`, a -`Vec`'s spare capacity, which [its own quest](/quest/m3/ts-unsafe/vec-spare-capacity.md) -owns, or a pointer kept in a field), `Bytes::slice_ref` of other storage, `alloc`'s bytes read as +JS keeps in two arrays, a pointer moved past the array JS keeps it in (`AtIndex.reach`, such +as one kept in a field), `Bytes::slice_ref` of other storage, `alloc`'s bytes read as values, ranges stepped without their type, and fmt widths written as a placeholder. `git grep 'rust2-ts: ' ts/runtime` lists them; classify each before fixing. The pointer comparisons [#584](https://github.com/moq-dev/rust2/pull/584) refuses at translation, where diff --git a/quest/m3/ts-unsafe/README.md b/quest/m3/ts-unsafe/README.md index 9945bbadd..baf2a6a84 100644 --- a/quest/m3/ts-unsafe/README.md +++ b/quest/m3/ts-unsafe/README.md @@ -70,7 +70,6 @@ Public API: the translator's output. ## Required -- [A Vec's spare capacity](/quest/m3/ts-unsafe/vec-spare-capacity.md) - writes through `as_mut_ptr` past the length, committed by `set_len`, translate for any `Vec` - [A raw pointer behind a reference](/quest/m3/ts-unsafe/raw-behind-ref.md) - `&raw const *r` of a value JS copies points where the reference came from - [Vec::from_raw_parts of a typed allocation](/quest/m3/ts-unsafe/vec-from-raw-parts.md) - a `Vec` adopts an `alloc`ed array of `T`s, with its length, capacity, and drops - [Unions over a type parameter](/quest/m3/ts-unsafe/generic-unions.md) - each instance of a generic union is laid out with its own offsets diff --git a/quest/m3/ts-unsafe/binary-heap-mir.md b/quest/m3/ts-unsafe/binary-heap-mir.md index b58cf4dcb..486400026 100644 --- a/quest/m3/ts-unsafe/binary-heap-mir.md +++ b/quest/m3/ts-unsafe/binary-heap-mir.md @@ -15,7 +15,3 @@ No consumer at the moq pin; the port works but must track std by hand. The B-tre [#577](https://github.com/moq-dev/rust2/pull/577) is the precedent. Public API: the translator's output. - -## Required - -- [A Vec's spare capacity](/quest/m3/ts-unsafe/vec-spare-capacity.md) - std's `PeekMut` calls `set_len` diff --git a/quest/m3/ts-unsafe/vec-drain-mir.md b/quest/m3/ts-unsafe/vec-drain-mir.md index 29ae3ef5d..891bbd26e 100644 --- a/quest/m3/ts-unsafe/vec-drain-mir.md +++ b/quest/m3/ts-unsafe/vec-drain-mir.md @@ -17,7 +17,3 @@ to std rather than a blocker: the port must track std by hand. The B-tree port o bench's drain-heavy workloads against the port. Public API: the translator's output. - -## Required - -- [A Vec's spare capacity](/quest/m3/ts-unsafe/vec-spare-capacity.md) - std's `Drain` calls `set_len` diff --git a/quest/m3/ts-unsafe/vec-spare-capacity.md b/quest/m3/ts-unsafe/vec-spare-capacity.md deleted file mode 100644 index 0382cc9fe..000000000 --- a/quest/m3/ts-unsafe/vec-spare-capacity.md +++ /dev/null @@ -1,25 +0,0 @@ -# [M] A Vec's spare capacity - -## Goal - -[rust2-ts](/ts/README.md) translates writes into a `Vec`'s spare capacity, through -`as_mut_ptr().add(len)` or `spare_capacity_mut`, committed by `set_len`, for any `T`, -proven by differential tests against native Rust. Today `set_len` is refused but for a -byte `Vec`'s (`unsupported call to std::vec::Vec::::set_len`, `ts/src/lower/body.rs`), -and a write past the length throws `a read or write through a pointer past the array JS -keeps it in` (`ts/runtime/rs/collections.ts`) where Rust defines it. - -## Plan - -`rs.Vec` holds std's capacity since [#555](https://github.com/moq-dev/rust2/pull/555); -the spare slots need to live outside the array's length until `set_len` takes them, as a -byte `Vec`'s do since [#568](https://github.com/moq-dev/rust2/pull/568). Removing the -run-time throw is also a gap of [Throw only where Rust panics](/quest/m3/ts-runtime-throws.md). -Copying a `MaybeUninit` slot never written is defined Rust and must translate, preserving -it as Rust does; only a read that produces an invalid `T` may abort, as a precondition -abort. - -No consumer at the moq pin. [Vec::drain](/quest/m3/ts-unsafe/vec-drain-mir.md) and -[BinaryHeap](/quest/m3/ts-unsafe/binary-heap-mir.md) from std's MIR need it. - -Public API: the translator's output. diff --git a/ts/README.md b/ts/README.md index d22d6891c..733c5cc90 100644 --- a/ts/README.md +++ b/ts/README.md @@ -110,7 +110,7 @@ crate translation reaches is refused, and so are two versions of one crate it re | `Vec` | `rs.Vec`: its items, the array `items`, and the capacity std's holds; `rs.vecFrom(items)` makes one of an array with room for exactly them. `rs.ByteVec` of bytes | | `Cow<[T]>`, `Cow` | `rs.Cow`: the `Vec` it owns, or an `rs.Borrowed` holding the slice it borrows; `rs.ByteCow` for bytes, an `rs.ByteVec` or an `rs.ByteSlice`; `rs.StrCow` for text, the `rs.String` it owns or an `rs.Borrowed` holding the string it borrows, whose text `rs.strCowStr` reads | | `&T`, `&mut T`, `Box`, `Reverse`, `NonZero`, `AssertUnwindSafe` | the value; a `&mut` to a value JS copies, such as a number, an `Option`, or a reference, or to an `Arc`, a `Waker`, or a `LocalKey`, whose copies share what it points at, is an `rs.Place`, which for what a box holds is the place holding the box | -| `*const T`, `*mut T`, `NonNull` | what a `&mut T` is: the object, an `rs.Slice` of a `[T; N]`'s elements or an `rs.ByteSlice` of a `[u8; N]`'s bytes, which compares by the array or buffer and offset they are at, refused for an array of one, which `array::from_ref`, `from_mut` of a variable, and `Option::as_slice` make of their own, or an `rs.Place` to a value JS copies and to a library type such as a `Vec` or an `Arc`, which into an array, slice, or `Vec` is the `rs.AtIndex` of its element, which `add`, `sub`, `offset`, their wrapping forms, `offset_from`, `ptr::copy`, and `slice::from_raw_parts` move, measure, copy between, and view; one to a value in no array is element 0 of an array of one, as in Rust; JS keeps that array, and a shared subslice, which JS copies, apart from what holds it in Rust, so a pointer, slice, or copy the body shows reaching past either, a raw or mutable slice of a byte in no array, and `offset_from` between pointers the body shows JS keeps in different arrays are refused, and through a pointer from elsewhere, such as a field, any of these, or a read or write past the array JS keeps it in, fails at run time; a pointer into an array of values JS keeps as objects is refused, as is comparing pointers to other values JS copies, each a place JS makes of its own; `rs.NULL` for null and `rs.DANGLING` for dangling. A `*const ()` is an identity, such as a waker's data, and `rs.DANGLING_UNIT` when dangling; one to a place of `()` or from a reference to one is refused. A pointer to a value JS keeps as an object cast to one, by `as` or `cast`, is the same object, which `rs.ptrErase` notes the type of, so a cast back to a pointer to another type fails at run time, and null and dangling stay so, dangling at the alignment of the type it was cast from; one to a value JS copies is the same place where an `Arc`'s or `Rc`'s `into_raw` or `as_ptr` gave it, its value's one place, which `rs.arcErase` checks where the body doesn't show it, and refused where the body shows a borrow's, a new place each borrow, as is casting one to a view of bytes, a new one each borrow, or one of no fixed size. A write of a whole object copies into it one object deep, as an assignment through a `&mut` does, the state an `rs` class such as `rs.LazyCell` keeps private included, so a pointer to a part kept as an object, such as a field of a tuple or struct type, is refused wherever the crate may put another object there while a pointer into that memory may still be read, which a write into a fresh allocation, or a variable before any pointer into it is taken, can't, whether by index or through std's iterators over its slots; a read copies what the crate writes into in place | +| `*const T`, `*mut T`, `NonNull` | what a `&mut T` is: the object, an `rs.Slice` of a `[T; N]`'s elements or an `rs.ByteSlice` of a `[u8; N]`'s bytes, which compares by the array or buffer and offset they are at, refused for an array of one, which `array::from_ref`, `from_mut` of a variable, and `Option::as_slice` make of their own, or an `rs.Place` to a value JS copies and to a library type such as a `Vec` or an `Arc`, which into an array, slice, or `Vec` is the `rs.AtIndex` of its element, which `add`, `sub`, `offset`, their wrapping forms, `offset_from`, `ptr::copy`, and `slice::from_raw_parts` move, measure, copy between, and view; one to a value in no array is element 0 of an array of one, as in Rust; JS keeps that array, and a shared subslice, which JS copies, apart from what holds it in Rust, so a pointer, slice, or copy the body shows reaching past either, a raw or mutable slice of a byte in no array, and `offset_from` between pointers the body shows JS keeps in different arrays are refused, and through a pointer from elsewhere, such as a field, any of these, or a read or write past the array JS keeps it in but for a `Vec`'s room up to its capacity, fails at run time; a pointer into an array of values JS keeps as objects is refused, as is comparing pointers to other values JS copies, each a place JS makes of its own; `rs.NULL` for null and `rs.DANGLING` for dangling. A `*const ()` is an identity, such as a waker's data, and `rs.DANGLING_UNIT` when dangling; one to a place of `()` or from a reference to one is refused. A pointer to a value JS keeps as an object cast to one, by `as` or `cast`, is the same object, which `rs.ptrErase` notes the type of, so a cast back to a pointer to another type fails at run time, and null and dangling stay so, dangling at the alignment of the type it was cast from; one to a value JS copies is the same place where an `Arc`'s or `Rc`'s `into_raw` or `as_ptr` gave it, its value's one place, which `rs.arcErase` checks where the body doesn't show it, and refused where the body shows a borrow's, a new place each borrow, as is casting one to a view of bytes, a new one each borrow, or one of no fixed size. A write of a whole object copies into it one object deep, as an assignment through a `&mut` does, the state an `rs` class such as `rs.LazyCell` keeps private included, so a pointer to a part kept as an object, such as a field of a tuple or struct type, is refused wherever the crate may put another object there while a pointer into that memory may still be read, which a write into a fresh allocation, or a variable before any pointer into it is taken, can't, whether by index or through std's iterators over its slots; a read copies what the crate writes into in place | | `MaybeUninit` | `T`: `undefined` until written, `0` for a byte, or an object whose parts kept as objects are there, holding `undefined`, as each of `Box::new_uninit_slice`'s is; a slice's `write_clone_of_slice` clones into its slots without dropping what they held | | `ManuallyDrop` | `T`, which nothing drops but its own `drop`; its `Debug`, comparisons, and constants are refused | | `union` | an object of slots named by offset, `at0` and `at8`, each holding the field part kept there; fields must overlap in the same type, or in a non-null pointer and an `Option` of it | @@ -1041,8 +1041,19 @@ they need. `push/vec`, and tracking it on each pop up to 2.8x on `push/stack` (decided with the maintainer on 2026-11-03). A `Vec`'s is its buffer's length, so its `spare_capacity_mut` is an `rs.ByteSlice` of the buffer past its length, which `set_len` - takes in, panicking past the capacity as std's check does, which can't unwind; any other `Vec`'s is refused, - as no JS array holds room past its length. Their `try_reserve` and `try_reserve_exact`, and a + takes in, panicking past the capacity as std's check does, which can't unwind. Any other + `Vec`'s items are a JS array as long as it is, which a write past its end would lengthen, + so the runtime keeps what Rust holds past its length apart, in an `rs.Room` by index. A + write past the length, up to the capacity, through a pointer from `as_ptr` or + `as_mut_ptr`, by `ptr::copy`, through a slice of the pointers, or through a slot of + `spare_capacity_mut`, a view of the items and the room, lands there; `set_len` takes slots + in and gives items up to it, so a pointer reads them back past the length, as std's + `Drain` and `retain` do. A slot never written holds what an unwritten `MaybeUninit` is, + which a copy keeps. A step other than `set_len` that shortens it, such as `pop` or + `truncate`, leaves the room as it was: std's `Vec` makes no promise to keep what it + removes, so the slot it gave up is uninitialized, and `set_len` requires every slot it + takes in to be initialized, which makes lengthening over that slot undefined in Rust + (decided with the maintainer on 2026-11-07). Their `try_reserve` and `try_reserve_exact`, and a `String`'s, give `Ok` where `reserve` makes room and `TryReserveError`'s `CapacityOverflow` where it panics, and `AllocError`, of the layout std's asks for, only where JS fails to allocate a byte `Vec`'s or `VecDeque`'s `Uint8Array` (decided with the diff --git a/ts/fixtures/lang/elements/expected/core/bool.ts b/ts/fixtures/lang/elements/expected/core/bool.ts index 12daf914b..8362caa47 100644 --- a/ts/fixtures/lang/elements/expected/core/bool.ts +++ b/ts/fixtures/lang/elements/expected/core/bool.ts @@ -9,4 +9,11 @@ export function thenSome$06c3xh5(self: boolean, t: [rs.u8, rs.u8]): [rs.u8, rs.u return t; } +export function thenSome$1gvhopg(self: boolean, t: rs.u16): rs.u16 | undefined { + if (!self) { + return undefined; + } + return t; +} + //# sourceMappingURL=bool.ts.map diff --git a/ts/fixtures/lang/elements/expected/core/option.ts b/ts/fixtures/lang/elements/expected/core/option.ts index 31b3f24ba..03bd70cd1 100644 --- a/ts/fixtures/lang/elements/expected/core/option.ts +++ b/ts/fixtures/lang/elements/expected/core/option.ts @@ -30,4 +30,11 @@ export function mapOr$13kt6x8(self: [rs.u8, rs.u8] | undefined, default_: Uint8A return f(self); } +export function mapOr$17z0l8m(self: rs.u16 | undefined, default_: Uint8Array, _: (a0: rs.u16) => Uint8Array): Uint8Array { + if (self === undefined) { + return default_; + } + return rs.u16ToBeBytes(self).reverse(); +} + //# sourceMappingURL=option.ts.map diff --git a/ts/fixtures/lang/elements/expected/elements.ts b/ts/fixtures/lang/elements/expected/elements.ts index a26fbaabb..e4f4687a2 100644 --- a/ts/fixtures/lang/elements/expected/elements.ts +++ b/ts/fixtures/lang/elements/expected/elements.ts @@ -20,7 +20,7 @@ export function vecs(data: rs.ByteSlice, out: rs.ByteVec): void { rs.iterExtend(v, rs.iterSlice([7, 8]), undefined, 4, true); const len: rs.usize = v.items.length; const at: rs.usize = rs.usizeRem(option_unwrapOr$1fr498u(rs.byteSliceFirst(data), 0) as rs.usize, rs.usizeSub(len, 1)); - const p: rs.Place = rs.arrayAsPtr(v.items); + const p: rs.Place = rs.vecAsPtr(v, 4); rs.ptrCopy(rs.ptrAdd(p, at), rs.ptrAdd(p, rs.usizeAdd(at, 1)), rs.usizeSub(rs.usizeSub(len, at), 1)); rs.ptrAdd(p, at).v = 1000; emit(rs.ptrSlice(p, len), out); @@ -41,9 +41,9 @@ export function vecs(data: rs.ByteSlice, out: rs.ByteVec): void { part.data[part.start] = rs.u32Add(part.data[part.start], 3); rs.sliceReverse(part); const w: rs.Vec = rs.vecFromElem(0, len, undefined); - rs.ptrCopy(p, rs.arrayAsPtr(w.items), len); - rs.ptrCopy(p, rs.ptrAdd(rs.arrayAsPtr(w.items), at), 1); - rs.ptrCopy(p, rs.ptrAdd(rs.arrayAsPtr(w.items), rs.usizeSub(len, 1)), 1); + rs.ptrCopy(p, rs.vecAsPtr(w, 4), len); + rs.ptrCopy(p, rs.ptrAdd(rs.vecAsPtr(w, 4), at), 1); + rs.ptrCopy(p, rs.ptrAdd(rs.vecAsPtr(w, 4), rs.usizeSub(len, 1)), 1); emit(rs.sliceFrom(w.items), out); emit(rs.sliceFrom(v.items), out); rs.byteVecPush(out, rs.ptrAdd(rs.sliceAsPtr(rs.sliceFrom(v.items)), rs.usizeDiv(len, 2)).v & 0xff); @@ -182,7 +182,7 @@ export function inline(data: rs.ByteSlice, out: rs.ByteVec): void { return [_22, 4] as [rs.u8, rs.u8]; })]).map(copy$Option_tuple2_u8_u8)); const dst: rs.Vec<[rs.u8, rs.u8] | undefined> = rs.vecFromElem(undefined as [rs.u8, rs.u8] | undefined, 3, copy$Option_tuple2_u8_u8); - rs.ptrCopy(rs.arrayAsPtr(src.items), rs.arrayAsPtr(dst.items), 3, copy$Option_tuple2_u8_u8); + rs.ptrCopy(rs.vecAsPtr(src, 3), rs.vecAsPtr(dst, 3), 3, copy$Option_tuple2_u8_u8); const at2 = rs.idx(dst.items, 0); if (dst.items[at2] !== undefined) { dst.items[at2][0] = 9; @@ -343,7 +343,7 @@ export function rawSlices(data: rs.ByteSlice, out: rs.ByteVec): void { return _2 as rs.u32; }), rs.iterSlice([5, 6, 7])), undefined, 4, true); const len: rs.usize = v.items.length; - const p: rs.RawSlice = new rs.RawSlice(rs.arrayAsPtr(v.items), len); + const p: rs.RawSlice = new rs.RawSlice(rs.vecAsPtr(v, 4), len); rs.idx(p, 0); const slice = p.deref(); const _19: rs.u32 = rs.u32Add(slice.data[slice.start], 1); @@ -381,7 +381,7 @@ export function rawSlices(data: rs.ByteSlice, out: rs.ByteVec): void { const long: rs.RawSlice = new rs.RawSlice(rs.sliceAsPtr(rs.sliceFrom(short)), 10); rs.byteVecPush(out, long.length & 0xff); rs.byteVecPush(out, rs.ptrAdd(long.ptr, 1).v & 0xff); - const pointer = rs.arrayAsPtr(v.items); + const pointer = rs.vecAsPtr(v, 4); const nn: rs.RawSlice = new rs.RawSlice(rs.optionUnwrap(pointer === rs.NULL ? undefined : pointer), 2); rs.byteVecPush(out, nn.length & 0xff); const _103: rs.RawSlice = nn; diff --git a/ts/fixtures/lang/elements/expected/lib.ts b/ts/fixtures/lang/elements/expected/lib.ts index 8c3aa4158..63ac32a2b 100644 --- a/ts/fixtures/lang/elements/expected/lib.ts +++ b/ts/fixtures/lang/elements/expected/lib.ts @@ -3,6 +3,7 @@ import * as rs from "./rs.ts"; import { vecs, arrays, segments, inline, edges, rawSlices, emptyParts } from "./elements.ts"; import * as Inline from "./elements.Inline.ts"; +import { spares } from "./spare.ts"; export function copy$Option_tuple2_u8_u8(v: [rs.u8, rs.u8] | undefined): [rs.u8, rs.u8] | undefined { return v === undefined ? v : copy$tuple2_u8_u8(v); @@ -26,6 +27,17 @@ export function copy$mem_MaybeUninit_array_Option_tuple2_u8_u8(v: Array<[rs.u8, return v.map(copy$mem_MaybeUninit_Option_tuple2_u8_u8); } +export function copy$mem_MaybeUninit_tuple2_u8_u32(v: [rs.u8, rs.u32]): [rs.u8, rs.u32] { + if (v === undefined) { + return v; + } + return [v[0], v[1]]; +} + +export function copy$tuple2_u8_u32(v: [rs.u8, rs.u32]): [rs.u8, rs.u32] { + return [v[0], v[1]]; +} + export function copy$tuple2_u8_u8(v: [rs.u8, rs.u8]): [rs.u8, rs.u8] { return [v[0], v[1]]; } @@ -43,21 +55,21 @@ export function drop$elements_Inline_sync_Arc_u8(_1: Inline.Inline * their count, so a case added at the end moves no other. */ export function cases(): rs.Vec<[string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]> { - return rs.vecFrom([["elements::vecs", (_24: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): undefined => { + return rs.vecFrom([["elements::vecs", (_27: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): undefined => { vecs(data, out); - }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::arrays", (_25: rs.u8, data2: rs.ByteSlice, out2: rs.ByteVec): undefined => { + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::arrays", (_28: rs.u8, data2: rs.ByteSlice, out2: rs.ByteVec): undefined => { arrays(data2, out2); - }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::segments", (_26: rs.u8, data3: rs.ByteSlice, out3: rs.ByteVec): undefined => { + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::segments", (_29: rs.u8, data3: rs.ByteSlice, out3: rs.ByteVec): undefined => { segments(data3, out3); - }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::inline", (_27: rs.u8, data4: rs.ByteSlice, out4: rs.ByteVec): undefined => { + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::inline", (_210: rs.u8, data4: rs.ByteSlice, out4: rs.ByteVec): undefined => { inline(data4, out4); - }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::edges", (_28: rs.u8, data5: rs.ByteSlice, out5: rs.ByteVec): undefined => { + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::edges", (_211: rs.u8, data5: rs.ByteSlice, out5: rs.ByteVec): undefined => { edges(data5, out5); - }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::raw_slices", (_29: rs.u8, data6: rs.ByteSlice, out6: rs.ByteVec): undefined => { + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::raw_slices", (_212: rs.u8, data6: rs.ByteSlice, out6: rs.ByteVec): undefined => { rawSlices(data6, out6); - }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::empty_parts", (_210: rs.u8, data7: rs.ByteSlice, out7: rs.ByteVec): undefined => { + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["elements::empty_parts", (_213: rs.u8, data7: rs.ByteSlice, out7: rs.ByteVec): undefined => { emptyParts(data7, out7); - }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]]); + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["spare::spares", spares as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]]); } //# sourceMappingURL=lib.ts.map diff --git a/ts/fixtures/lang/elements/expected/spare.Noted.ts b/ts/fixtures/lang/elements/expected/spare.Noted.ts new file mode 100644 index 000000000..9afcd303b --- /dev/null +++ b/ts/fixtures/lang/elements/expected/spare.Noted.ts @@ -0,0 +1,38 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import { DROPS } from "./spare.ts"; + +export function clone$Clone(self: Noted): Noted { + return new Noted(self._0); +} + +/** + * A value that counts its drops, so what `set_len` gives up shows it drops nothing. JS + * keeps it as an object, so no pointer into a `Vec` of them is modeled. + */ +export class Noted { + _0: rs.u8; + + constructor(_0: rs.u8) { + this._0 = _0; + } + + [Symbol.dispose](): void { + drop$ops_Drop(this); + } +} + +export function drop$ops_Drop(_self: Noted): void { + rs.atomicFetch(DROPS, rs.u8WrappingAdd, 1, 0); +} + +export function of$spare_Item(n: rs.u8): Noted { + return new Noted(n); +} + +export function put$spare_Item(self: Noted, out: rs.ByteVec): void { + rs.byteVecPush(out, self._0); +} + +//# sourceMappingURL=spare.Noted.ts.map diff --git a/ts/fixtures/lang/elements/expected/spare.Ops.ts b/ts/fixtures/lang/elements/expected/spare.Ops.ts new file mode 100644 index 000000000..8d221afa1 --- /dev/null +++ b/ts/fixtures/lang/elements/expected/spare.Ops.ts @@ -0,0 +1,26 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** The bytes a case reads its steps from. */ +export interface Ops { + _0Data: Uint8Array; + _0Start: number; + _0Len: number; +} + +export function byte(self: Ops): rs.u8 { + const _6Data: Uint8Array = self._0Data; + const _6Start: number = self._0Start; + const _6Len: number = self._0Len; + if (_6Len !== 0) { + const b: rs.u8 = _6Data[_6Start]; + self._0Data = _6Data; + self._0Start = _6Start + 1; + self._0Len = _6Len - 1; + return b; + } + return 0; +} + +//# sourceMappingURL=spare.Ops.ts.map diff --git a/ts/fixtures/lang/elements/expected/spare.Pair.ts b/ts/fixtures/lang/elements/expected/spare.Pair.ts new file mode 100644 index 000000000..a503e6967 --- /dev/null +++ b/ts/fixtures/lang/elements/expected/spare.Pair.ts @@ -0,0 +1,26 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import { put$spare_Item_String as spare_put$spare_Item_String } from "./spare.ts"; + +export function clone$Clone(self: Pair): Pair { + return { a: self.a, b: rs.stringClone(self.b) }; +} + +/** A struct JS keeps as an object. */ +export interface Pair { + a: rs.u8; + b: rs.String; +} + +export function of$spare_Item(n: rs.u8): Pair { + const _2: rs.String = rs.fmtToString((f: rs.Formatter) => rs.u8Display(n, f), 0); + return { a: n, b: _2 }; +} + +export function put$spare_Item(self: Pair, out: rs.ByteVec): void { + rs.byteVecPush(out, self.a); + spare_put$spare_Item_String(self.b, out); +} + +//# sourceMappingURL=spare.Pair.ts.map diff --git a/ts/fixtures/lang/elements/expected/spare.ts b/ts/fixtures/lang/elements/expected/spare.ts new file mode 100644 index 000000000..33f182bbe --- /dev/null +++ b/ts/fixtures/lang/elements/expected/spare.ts @@ -0,0 +1,1170 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import { copy$mem_MaybeUninit_tuple2_u8_u32, copy$tuple2_u8_u32 } from "./lib.ts"; +import { thenSome$1gvhopg } from "./core/bool.ts"; +import { mapOr$17z0l8m as option_mapOr$17z0l8m } from "./core/option.ts"; +import * as Noted from "./spare.Noted.ts"; +import * as Ops from "./spare.Ops.ts"; +import * as Pair from "./spare.Pair.ts"; + +export function of$spare_Item_u32(n: rs.u8): rs.u32 { + return rs.u32Mul(n as rs.u32, 257); +} + +export function put$spare_Item_u32(self: rs.u32, out: rs.ByteVec): void { + rs.byteVecExtendFromSlice(out, rs.byteSliceFrom(rs.u32ToBeBytes(self).reverse())); +} + +export function of$spare_Item_String(n: rs.u8): rs.String { + return rs.fmtFormat([(f: rs.Formatter) => rs.u8LowerHex(n, f)]); +} + +export function put$spare_Item_String(self: rs.String, out: rs.ByteVec): void { + rs.byteVecExtendFromSlice(out, rs.stringAsBytes(self.v)); + rs.byteVecPush(out, 255); +} + +export function of$spare_Item_Option_u16(n: rs.u8): rs.u16 | undefined { + return thenSome$1gvhopg(rs.u8Rem(n, 3) !== 0, ((n as rs.u16) << 4) & 0xffff); +} + +export function put$spare_Item_Option_u16(self: rs.u16 | undefined, out: rs.ByteVec): void { + rs.iterExtendBytes(out, rs.iterSlice(option_mapOr$17z0l8m(self, Uint8Array.of(238, 238), (a0: rs.u16): Uint8Array => { + return rs.u16ToBeBytes(a0).reverse(); + })), undefined, true); +} + +export const DROPS: rs.Atomic = /* @__PURE__ */ new rs.Atomic(0); + +export function of$spare_Item_tuple2_u8_u32(n: rs.u8): [rs.u8, rs.u32] { + return [n, rs.u32Add(n as rs.u32, 1)] as [rs.u8, rs.u32]; +} + +export function put$spare_Item_tuple2_u8_u32(self: [rs.u8, rs.u32], out: rs.ByteVec): void { + rs.byteVecPush(out, self[0]); + put$spare_Item_u32(self[1], out); +} + +/** The length, capacity, and room of `v`, how many `Noted`s dropped, and its items. */ +export function state$Option_u16(v: rs.Vec, out: rs.ByteVec): void { + const iter: rs.Iter = rs.iterSlice([v.items.length, rs.vecCapacity(v, 4), rs.vecSpare(v, 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }).length]); + while (true) { + const _13: rs.usize | rs.Done = iter.next(); + if (_13 === rs.DONE) { + break; + } + rs.byteVecExtendFromSlice(out, rs.byteSliceFrom(rs.u32ToBeBytes(_13 as rs.u32).reverse())); + } + rs.byteVecPush(out, rs.atomicLoad(DROPS, 0)); + const iter2: rs.Iter = rs.iterSlice(v.items); + while (true) { + const _31: rs.u16 | undefined | rs.Done = iter2.next(); + if (_31 === rs.DONE) { + break; + } + put$spare_Item_Option_u16(_31, out); + } +} + +/** The length, capacity, and room of `v`, how many `Noted`s dropped, and its items. */ +export function state$String(v: rs.Vec, out: rs.ByteVec): void { + const iter: rs.Iter = rs.iterSlice([v.items.length, rs.vecCapacity(v, 12), rs.vecSpare(v, 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }).length]); + while (true) { + const _13: rs.usize | rs.Done = iter.next(); + if (_13 === rs.DONE) { + break; + } + rs.byteVecExtendFromSlice(out, rs.byteSliceFrom(rs.u32ToBeBytes(_13 as rs.u32).reverse())); + } + rs.byteVecPush(out, rs.atomicLoad(DROPS, 0)); + const iter2: rs.Iter = rs.iterSlice(v.items); + while (true) { + const _31: rs.String | rs.Done = iter2.next(); + if (_31 === rs.DONE) { + break; + } + put$spare_Item_String(_31, out); + } +} + +/** The length, capacity, and room of `v`, how many `Noted`s dropped, and its items. */ +export function state$spare_Noted(v: rs.Vec, out: rs.ByteVec): void { + const iter: rs.Iter = rs.iterSlice([v.items.length, rs.vecCapacity(v, 1), rs.vecSpare(v, 1, (): Noted.Noted => { + return (new Noted.Noted((undefined as unknown) as rs.u8) as unknown) as Noted.Noted; + }).length]); + while (true) { + const _13: rs.usize | rs.Done = iter.next(); + if (_13 === rs.DONE) { + break; + } + rs.byteVecExtendFromSlice(out, rs.byteSliceFrom(rs.u32ToBeBytes(_13 as rs.u32).reverse())); + } + rs.byteVecPush(out, rs.atomicLoad(DROPS, 0)); + const iter2: rs.Iter = rs.iterSlice(v.items); + while (true) { + const _31: Noted.Noted | rs.Done = iter2.next(); + if (_31 === rs.DONE) { + break; + } + Noted.put$spare_Item(_31, out); + } +} + +/** The length, capacity, and room of `v`, how many `Noted`s dropped, and its items. */ +export function state$spare_Pair(v: rs.Vec, out: rs.ByteVec): void { + const iter: rs.Iter = rs.iterSlice([v.items.length, rs.vecCapacity(v, 16), rs.vecSpare(v, 16, (): Pair.Pair => { + return ({ a: undefined, b: undefined } as unknown) as Pair.Pair; + }).length]); + while (true) { + const _13: rs.usize | rs.Done = iter.next(); + if (_13 === rs.DONE) { + break; + } + rs.byteVecExtendFromSlice(out, rs.byteSliceFrom(rs.u32ToBeBytes(_13 as rs.u32).reverse())); + } + rs.byteVecPush(out, rs.atomicLoad(DROPS, 0)); + const iter2: rs.Iter = rs.iterSlice(v.items); + while (true) { + const _31: Pair.Pair | rs.Done = iter2.next(); + if (_31 === rs.DONE) { + break; + } + Pair.put$spare_Item(_31, out); + } +} + +/** The length, capacity, and room of `v`, how many `Noted`s dropped, and its items. */ +export function state$tuple2_u8_u32(v: rs.Vec<[rs.u8, rs.u32]>, out: rs.ByteVec): void { + const iter: rs.Iter = rs.iterSlice([v.items.length, rs.vecCapacity(v, 8), rs.vecSpare(v, 8, (): [rs.u8, rs.u32] => { + return ([undefined, undefined] as unknown) as [rs.u8, rs.u32]; + }).length]); + while (true) { + const _13: rs.usize | rs.Done = iter.next(); + if (_13 === rs.DONE) { + break; + } + rs.byteVecExtendFromSlice(out, rs.byteSliceFrom(rs.u32ToBeBytes(_13 as rs.u32).reverse())); + } + rs.byteVecPush(out, rs.atomicLoad(DROPS, 0)); + const iter2: rs.Iter<[rs.u8, rs.u32]> = rs.iterSlice(v.items); + while (true) { + const _31: [rs.u8, rs.u32] | rs.Done = iter2.next(); + if (_31 === rs.DONE) { + break; + } + put$spare_Item_tuple2_u8_u32(_31, out); + } +} + +/** The length, capacity, and room of `v`, how many `Noted`s dropped, and its items. */ +export function state$u32(v: rs.Vec, out: rs.ByteVec): void { + const iter: rs.Iter = rs.iterSlice([v.items.length, rs.vecCapacity(v, 4), rs.vecSpare(v, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }).length]); + while (true) { + const _13: rs.usize | rs.Done = iter.next(); + if (_13 === rs.DONE) { + break; + } + rs.byteVecExtendFromSlice(out, rs.byteSliceFrom(rs.u32ToBeBytes(_13 as rs.u32).reverse())); + } + rs.byteVecPush(out, rs.atomicLoad(DROPS, 0)); + const iter2: rs.Iter = rs.iterSlice(v.items); + while (true) { + const _31: rs.u32 | rs.Done = iter2.next(); + if (_31 === rs.DONE) { + break; + } + put$spare_Item_u32(_31, out); + } +} + +/** + * A vector of values JS copies, written past its length through pointers, by element, by + * `ptr::copy_nonoverlapping`, and through a slice made of them, and taken in by + * `set_len`, of the `Vec` itself or of the one it moved to; an insert that moves the tail into the room, as std's does; a removal of a + * run that shortens it by `set_len` first and reads the run past its length, as std's + * `Drain` does; a filter that shortens it to nothing and writes back what it keeps, as + * std's `retain` does; grown, cut, and refilled. + */ +export function pointers$Option_u16(data: rs.ByteSlice, out: rs.ByteVec): void { + let _43!: rs.usize; + let _155!: rs.usize; + let _184!: rs.usize; + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 4); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const _20: [rs.usize, rs.usize] = [v.items.length, rs.usizeSub(rs.vecCapacity(v, 4), v.items.length)]; + const len: rs.usize = _20[0]; + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(_20[1], 1)); + b2: { + const _35: rs.u8 = rs.u8Rem(op, 8); + if (_35 === 0) { + const end: rs.Place = rs.ptrAdd(rs.vecAsPtr(v, 4), len); + let iterStart: rs.usize = 0; + const iterEnd: rs.usize = k; + while ((_43 = iterStart++) < iterEnd) { + const i: rs.usize = _43; + rs.ptrAdd(end, i).v = of$spare_Item_Option_u16(rs.u8WrappingAdd(n, i & 0xff)); + } + const moved: rs.Vec = rs.replaceIn(v, new rs.Vec()); + for (const _61 of rs.sliceItems(rs.ptrSlice(rs.ptrAdd(end, -len), rs.usizeAdd(len, k)))) { + put$spare_Item_Option_u16(_61, out); + } + rs.vecSetLen(moved, rs.usizeAdd(len, k), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + v = moved; + break b2; + } + if (_35 === 1) { + rs.ptrCopy(rs.vecAsPtr(rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i5: rs.usize): rs.u16 | undefined => { + return of$spare_Item_Option_u16(n ^ (i5 & 0xff)); + }), undefined, 4, true), 4), rs.ptrAdd(rs.vecAsPtr(v, 4), len), k); + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + break b2; + } + if (_35 === 2) { + const iter3: rs.Iter<[rs.usize, rs.Place]> = rs.iterRev(rs.iterEnumerate(rs.iterSliceMut(rs.ptrSlice(rs.ptrAdd(rs.vecAsPtr(v, 4), len), k)))); + while (true) { + const _98: [rs.usize, rs.Place] | rs.Done = iter3.next(); + if (_98 === rs.DONE) { + break; + } + _98[1].v = of$spare_Item_Option_u16(rs.u8WrappingSub(n, _98[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + break b2; + } + if (_35 === 3) { + rs.vecReserve(v, 1, 4); + const at: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1)); + const p: rs.Place = rs.ptrAdd(rs.vecAsPtr(v, 4), at); + rs.ptrCopy(p, rs.ptrAdd(p, 1), rs.usizeSub(len, at)); + p.v = of$spare_Item_Option_u16(n); + rs.vecSetLen(v, rs.usizeAdd(len, 1), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + break b2; + } + if (_35 === 4) { + if (len > 0) { + const at2: rs.usize = rs.usizeRem(n as rs.usize, len); + const end2: rs.usize = rs.usizeAdd(at2, rs.usizeRem(n >> 4 as rs.usize, rs.usizeAdd(rs.usizeSub(len, at2), 1))); + rs.vecSetLen(v, at2, 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + const p2: rs.Place = rs.vecAsPtr(v, 4); + let iterStart2: rs.usize = at2; + const iterEnd2: rs.usize = end2; + while ((_155 = iterStart2++) < iterEnd2) { + put$spare_Item_Option_u16(rs.ptrAdd(p2, _155).v, out); + } + rs.ptrCopy(rs.ptrAdd(p2, end2), rs.ptrAdd(p2, at2), rs.usizeSub(len, end2)); + rs.vecSetLen(v, rs.usizeSub(len, rs.usizeSub(end2, at2)), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + break b2; + } + } else { + if (_35 === 5) { + rs.vecSetLen(v, 0, 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + const p3: rs.Place = rs.vecAsPtr(v, 4); + let kept: rs.usize = 0; + let iterStart3: rs.usize = 0; + const iterEnd3: rs.usize = len; + while ((_184 = iterStart3++) < iterEnd3) { + const i4: rs.usize = _184; + const x: rs.u16 | undefined = rs.ptrAdd(p3, i4).v; + if (rs.usizeRem(rs.usizeAdd(i4, n as rs.usize), 3) !== 0) { + rs.ptrAdd(p3, kept).v = x; + kept = rs.usizeAdd(kept, 1); + } + } + rs.vecSetLen(v, kept, 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + break b2; + } + if (_35 === 6) { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 4); + break b2; + } + } + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1))); + } + state$Option_u16(v, out); + } +} + +/** + * A vector of values JS copies, written past its length through pointers, by element, by + * `ptr::copy_nonoverlapping`, and through a slice made of them, and taken in by + * `set_len`, of the `Vec` itself or of the one it moved to; an insert that moves the tail into the room, as std's does; a removal of a + * run that shortens it by `set_len` first and reads the run past its length, as std's + * `Drain` does; a filter that shortens it to nothing and writes back what it keeps, as + * std's `retain` does; grown, cut, and refilled. + */ +export function pointers$String(data: rs.ByteSlice, out: rs.ByteVec): void { + let _43!: rs.usize; + let _155!: rs.usize; + let _184!: rs.usize; + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 12); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const _20: [rs.usize, rs.usize] = [v.items.length, rs.usizeSub(rs.vecCapacity(v, 12), v.items.length)]; + const len: rs.usize = _20[0]; + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(_20[1], 1)); + b2: { + const _35: rs.u8 = rs.u8Rem(op, 8); + if (_35 === 0) { + const end: rs.Place = rs.ptrAdd(rs.vecAsPtr(v, 12), len); + let iterStart: rs.usize = 0; + const iterEnd: rs.usize = k; + while ((_43 = iterStart++) < iterEnd) { + const i: rs.usize = _43; + rs.ptrAdd(end, i).v = of$spare_Item_String(rs.u8WrappingAdd(n, i & 0xff)); + } + const moved: rs.Vec = rs.replaceIn(v, new rs.Vec()); + for (const _61 of rs.sliceItems(rs.ptrSlice(rs.ptrAdd(end, -len), rs.usizeAdd(len, k)))) { + put$spare_Item_String(_61, out); + } + rs.vecSetLen(moved, rs.usizeAdd(len, k), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + v = moved; + break b2; + } + if (_35 === 1) { + rs.ptrCopy(rs.vecAsPtr(rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i5: rs.usize): rs.String => { + return of$spare_Item_String(n ^ (i5 & 0xff)); + }), undefined, 12, true), 12), rs.ptrAdd(rs.vecAsPtr(v, 12), len), k); + rs.vecSetLen(v, rs.usizeAdd(len, k), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + break b2; + } + if (_35 === 2) { + const iter3: rs.Iter<[rs.usize, rs.Place]> = rs.iterRev(rs.iterEnumerate(rs.iterSliceMut(rs.ptrSlice(rs.ptrAdd(rs.vecAsPtr(v, 12), len), k)))); + while (true) { + const _98: [rs.usize, rs.Place] | rs.Done = iter3.next(); + if (_98 === rs.DONE) { + break; + } + _98[1].v = of$spare_Item_String(rs.u8WrappingSub(n, _98[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + break b2; + } + if (_35 === 3) { + rs.vecReserve(v, 1, 12); + const at: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1)); + const p: rs.Place = rs.ptrAdd(rs.vecAsPtr(v, 12), at); + rs.ptrCopy(p, rs.ptrAdd(p, 1), rs.usizeSub(len, at)); + p.v = of$spare_Item_String(n); + rs.vecSetLen(v, rs.usizeAdd(len, 1), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + break b2; + } + if (_35 === 4) { + if (len > 0) { + const at2: rs.usize = rs.usizeRem(n as rs.usize, len); + const end2: rs.usize = rs.usizeAdd(at2, rs.usizeRem(n >> 4 as rs.usize, rs.usizeAdd(rs.usizeSub(len, at2), 1))); + rs.vecSetLen(v, at2, 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + const p2: rs.Place = rs.vecAsPtr(v, 12); + let iterStart2: rs.usize = at2; + const iterEnd2: rs.usize = end2; + while ((_155 = iterStart2++) < iterEnd2) { + put$spare_Item_String(rs.ptrAdd(p2, _155).v, out); + } + rs.ptrCopy(rs.ptrAdd(p2, end2), rs.ptrAdd(p2, at2), rs.usizeSub(len, end2)); + rs.vecSetLen(v, rs.usizeSub(len, rs.usizeSub(end2, at2)), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + break b2; + } + } else { + if (_35 === 5) { + rs.vecSetLen(v, 0, 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + const p3: rs.Place = rs.vecAsPtr(v, 12); + let kept: rs.usize = 0; + let iterStart3: rs.usize = 0; + const iterEnd3: rs.usize = len; + while ((_184 = iterStart3++) < iterEnd3) { + const i4: rs.usize = _184; + const x: rs.String = rs.ptrAdd(p3, i4).v; + if (rs.usizeRem(rs.usizeAdd(i4, n as rs.usize), 3) !== 0) { + rs.ptrAdd(p3, kept).v = x; + kept = rs.usizeAdd(kept, 1); + } + } + rs.vecSetLen(v, kept, 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + break b2; + } + if (_35 === 6) { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 12); + break b2; + } + } + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1))); + } + state$String(v, out); + } +} + +/** + * A vector of values JS copies, written past its length through pointers, by element, by + * `ptr::copy_nonoverlapping`, and through a slice made of them, and taken in by + * `set_len`, of the `Vec` itself or of the one it moved to; an insert that moves the tail into the room, as std's does; a removal of a + * run that shortens it by `set_len` first and reads the run past its length, as std's + * `Drain` does; a filter that shortens it to nothing and writes back what it keeps, as + * std's `retain` does; grown, cut, and refilled. + */ +export function pointers$u32(data: rs.ByteSlice, out: rs.ByteVec): void { + let _43!: rs.usize; + let _155!: rs.usize; + let _184!: rs.usize; + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 4); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const _20: [rs.usize, rs.usize] = [v.items.length, rs.usizeSub(rs.vecCapacity(v, 4), v.items.length)]; + const len: rs.usize = _20[0]; + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(_20[1], 1)); + b2: { + const _35: rs.u8 = rs.u8Rem(op, 8); + if (_35 === 0) { + const end: rs.Place = rs.ptrAdd(rs.vecAsPtr(v, 4), len); + let iterStart: rs.usize = 0; + const iterEnd: rs.usize = k; + while ((_43 = iterStart++) < iterEnd) { + const i: rs.usize = _43; + rs.ptrAdd(end, i).v = of$spare_Item_u32(rs.u8WrappingAdd(n, i & 0xff)); + } + const moved: rs.Vec = rs.replaceIn(v, new rs.Vec()); + for (const _61 of rs.sliceItems(rs.ptrSlice(rs.ptrAdd(end, -len), rs.usizeAdd(len, k)))) { + put$spare_Item_u32(_61, out); + } + rs.vecSetLen(moved, rs.usizeAdd(len, k), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + v = moved; + break b2; + } + if (_35 === 1) { + rs.ptrCopy(rs.vecAsPtr(rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i5: rs.usize): rs.u32 => { + return of$spare_Item_u32(n ^ (i5 & 0xff)); + }), undefined, 4, true), 4), rs.ptrAdd(rs.vecAsPtr(v, 4), len), k); + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + break b2; + } + if (_35 === 2) { + const iter3: rs.Iter<[rs.usize, rs.Place]> = rs.iterRev(rs.iterEnumerate(rs.iterSliceMut(rs.ptrSlice(rs.ptrAdd(rs.vecAsPtr(v, 4), len), k)))); + while (true) { + const _98: [rs.usize, rs.Place] | rs.Done = iter3.next(); + if (_98 === rs.DONE) { + break; + } + _98[1].v = of$spare_Item_u32(rs.u8WrappingSub(n, _98[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + break b2; + } + if (_35 === 3) { + rs.vecReserve(v, 1, 4); + const at: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1)); + const p: rs.Place = rs.ptrAdd(rs.vecAsPtr(v, 4), at); + rs.ptrCopy(p, rs.ptrAdd(p, 1), rs.usizeSub(len, at)); + p.v = of$spare_Item_u32(n); + rs.vecSetLen(v, rs.usizeAdd(len, 1), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + break b2; + } + if (_35 === 4) { + if (len > 0) { + const at2: rs.usize = rs.usizeRem(n as rs.usize, len); + const end2: rs.usize = rs.usizeAdd(at2, rs.usizeRem(n >> 4 as rs.usize, rs.usizeAdd(rs.usizeSub(len, at2), 1))); + rs.vecSetLen(v, at2, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + const p2: rs.Place = rs.vecAsPtr(v, 4); + let iterStart2: rs.usize = at2; + const iterEnd2: rs.usize = end2; + while ((_155 = iterStart2++) < iterEnd2) { + put$spare_Item_u32(rs.ptrAdd(p2, _155).v, out); + } + rs.ptrCopy(rs.ptrAdd(p2, end2), rs.ptrAdd(p2, at2), rs.usizeSub(len, end2)); + rs.vecSetLen(v, rs.usizeSub(len, rs.usizeSub(end2, at2)), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + break b2; + } + } else { + if (_35 === 5) { + rs.vecSetLen(v, 0, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + const p3: rs.Place = rs.vecAsPtr(v, 4); + let kept: rs.usize = 0; + let iterStart3: rs.usize = 0; + const iterEnd3: rs.usize = len; + while ((_184 = iterStart3++) < iterEnd3) { + const i4: rs.usize = _184; + const x: rs.u32 = rs.ptrAdd(p3, i4).v; + if (rs.usizeRem(rs.usizeAdd(i4, n as rs.usize), 3) !== 0) { + rs.ptrAdd(p3, kept).v = x; + kept = rs.usizeAdd(kept, 1); + } + } + rs.vecSetLen(v, kept, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + break b2; + } + if (_35 === 6) { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 4); + break b2; + } + } + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1))); + } + state$u32(v, out); + } +} + +/** + * A vector of any items written through the slots `spare_capacity_mut` lends: by + * `write`, by assigning one whole, by `write_clone_of_slice` and through the slice it + * gives back, and by `fill_with`, then taken in by `set_len`; one written and read back before + * any `set_len`, and written over by a second call, then taken in by the `Vec` it was + * swapped into; grown and cut. + */ +export function slots$Option_u16(data: rs.ByteSlice, out: rs.ByteVec): void { + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 4); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const len: rs.usize = v.items.length; + const spare: rs.Slice = rs.vecSpare(v, 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(spare.length, 1)); + const _30: rs.u8 = rs.u8Rem(op, 6); + if (_30 === 0) { + const iter: rs.Iter<[rs.usize, rs.Place]> = rs.iterEnumerate(rs.iterSliceMut(rs.sliceRange(spare, 0, k))); + while (true) { + const _38: [rs.usize, rs.Place] | rs.Done = iter.next(); + if (_38 === rs.DONE) { + break; + } + _38[1].v = of$spare_Item_Option_u16(n ^ (_38[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + } else if (_30 === 1) { + const iter2: rs.Iter<[rs.usize, rs.Place]> = rs.iterRev(rs.iterEnumerate(rs.iterSliceMut(rs.sliceRange(spare, 0, k)))); + while (true) { + const _58: [rs.usize, rs.Place] | rs.Done = iter2.next(); + if (_58 === rs.DONE) { + break; + } + _58[1].v = of$spare_Item_Option_u16(rs.u8WrappingAdd(n, _58[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + } else if (_30 === 2) { + const src: rs.Vec = rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i3: rs.usize): rs.u16 | undefined => { + return of$spare_Item_Option_u16(rs.u8WrappingMul(n, i3 & 0xff)); + }), undefined, 4, true); + rs.sliceReverse(rs.sliceWriteCloneOfSlice(rs.sliceRange(spare, 0, k), rs.sliceFrom(src.items), undefined)); + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + } else if (_30 === 3) { + rs.sliceFillWith(rs.sliceRange(spare, 0, k), (): rs.u16 | undefined => { + return of$spare_Item_Option_u16(n); + }); + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + } else if (_30 === 4) { + const _95: rs.Place | undefined = rs.sliceFirstMut(spare); + if (_95 !== undefined) { + _95.v = of$spare_Item_Option_u16(~n & 0xff); + put$spare_Item_Option_u16(_95.v, out); + } + const _105: rs.Place | undefined = rs.sliceFirstMut(rs.vecSpare(v, 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + })); + if (_105 !== undefined) { + _105.v = of$spare_Item_Option_u16(n); + let swapped: rs.Vec = new rs.Vec(); + swapped = rs.replaceIn(v, swapped); + rs.vecSetLen(swapped, rs.usizeAdd(len, 1), 4, (): rs.u16 | undefined => { + return (undefined as unknown) as rs.u16 | undefined; + }); + v = swapped; + } + } else if (!(rs.u8Rem(n, 2) === 0)) { + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1))); + } else { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 4); + } + state$Option_u16(v, out); + } +} + +/** + * A vector of any items written through the slots `spare_capacity_mut` lends: by + * `write`, by assigning one whole, by `write_clone_of_slice` and through the slice it + * gives back, and by `fill_with`, then taken in by `set_len`; one written and read back before + * any `set_len`, and written over by a second call, then taken in by the `Vec` it was + * swapped into; grown and cut. + */ +export function slots$String(data: rs.ByteSlice, out: rs.ByteVec): void { + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 12); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const len: rs.usize = v.items.length; + const spare: rs.Slice = rs.vecSpare(v, 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(spare.length, 1)); + const _30: rs.u8 = rs.u8Rem(op, 6); + if (_30 === 0) { + const iter: rs.Iter<[rs.usize, rs.Place]> = rs.iterEnumerate(rs.iterSliceMut(rs.sliceRange(spare, 0, k))); + while (true) { + const _38: [rs.usize, rs.Place] | rs.Done = iter.next(); + if (_38 === rs.DONE) { + break; + } + _38[1].v = of$spare_Item_String(n ^ (_38[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + } else if (_30 === 1) { + const iter2: rs.Iter<[rs.usize, rs.Place]> = rs.iterRev(rs.iterEnumerate(rs.iterSliceMut(rs.sliceRange(spare, 0, k)))); + while (true) { + const _58: [rs.usize, rs.Place] | rs.Done = iter2.next(); + if (_58 === rs.DONE) { + break; + } + _58[1].v = of$spare_Item_String(rs.u8WrappingAdd(n, _58[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + } else if (_30 === 2) { + const src: rs.Vec = rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i3: rs.usize): rs.String => { + return of$spare_Item_String(rs.u8WrappingMul(n, i3 & 0xff)); + }), undefined, 12, true); + rs.sliceReverse(rs.sliceWriteCloneOfSlice(rs.sliceRange(spare, 0, k), rs.sliceFrom(src.items), (a0: rs.String): rs.String => { + return rs.stringClone(a0); + })); + rs.vecSetLen(v, rs.usizeAdd(len, k), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + } else if (_30 === 3) { + rs.sliceFillWith(rs.sliceRange(spare, 0, k), (): rs.String => { + return of$spare_Item_String(n); + }); + rs.vecSetLen(v, rs.usizeAdd(len, k), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + } else if (_30 === 4) { + const _95: rs.Place | undefined = rs.sliceFirstMut(spare); + if (_95 !== undefined) { + _95.v = of$spare_Item_String(~n & 0xff); + put$spare_Item_String(_95.v, out); + } + const _105: rs.Place | undefined = rs.sliceFirstMut(rs.vecSpare(v, 12, (): rs.String => { + return (undefined as unknown) as rs.String; + })); + if (_105 !== undefined) { + _105.v = of$spare_Item_String(n); + let swapped: rs.Vec = new rs.Vec(); + swapped = rs.replaceIn(v, swapped); + rs.vecSetLen(swapped, rs.usizeAdd(len, 1), 12, (): rs.String => { + return (undefined as unknown) as rs.String; + }); + v = swapped; + } + } else if (!(rs.u8Rem(n, 2) === 0)) { + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1))); + } else { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 12); + } + state$String(v, out); + } +} + +/** + * A vector of any items written through the slots `spare_capacity_mut` lends: by + * `write`, by assigning one whole, by `write_clone_of_slice` and through the slice it + * gives back, and by `fill_with`, then taken in by `set_len`; one written and read back before + * any `set_len`, and written over by a second call, then taken in by the `Vec` it was + * swapped into; grown and cut. + */ +export function slots$spare_Noted(data: rs.ByteSlice, out: rs.ByteVec): void { + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 1); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const len: rs.usize = v.items.length; + const spare: rs.Slice = rs.vecSpare(v, 1, (): Noted.Noted => { + return (new Noted.Noted((undefined as unknown) as rs.u8) as unknown) as Noted.Noted; + }); + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(spare.length, 1)); + const _30: rs.u8 = rs.u8Rem(op, 6); + if (_30 === 0) { + const iter: rs.Iter<[rs.usize, Noted.Noted]> = rs.iterEnumerate(rs.iterSlice(rs.sliceItems(rs.sliceRange(spare, 0, k)))); + while (true) { + const _38: [rs.usize, Noted.Noted] | rs.Done = iter.next(); + if (_38 === rs.DONE) { + break; + } + rs.ptrWrite(_38[1], Noted.of$spare_Item(n ^ (_38[0] & 0xff))); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 1, (): Noted.Noted => { + return (new Noted.Noted((undefined as unknown) as rs.u8) as unknown) as Noted.Noted; + }); + } else if (_30 === 1) { + const iter2: rs.Iter<[rs.usize, Noted.Noted]> = rs.iterRev(rs.iterEnumerate(rs.iterSlice(rs.sliceItems(rs.sliceRange(spare, 0, k))))); + while (true) { + const _58: [rs.usize, Noted.Noted] | rs.Done = iter2.next(); + if (_58 === rs.DONE) { + break; + } + Object.assign(_58[1], Noted.of$spare_Item(rs.u8WrappingAdd(n, _58[0] & 0xff))); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 1, (): Noted.Noted => { + return (new Noted.Noted((undefined as unknown) as rs.u8) as unknown) as Noted.Noted; + }); + } else if (_30 === 2) { + const src: rs.Vec = rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i3: rs.usize): Noted.Noted => { + return Noted.of$spare_Item(rs.u8WrappingMul(n, i3 & 0xff)); + }), undefined, 1, true); + rs.sliceReverse(rs.sliceWriteCloneOfSlice(rs.sliceRange(spare, 0, k), rs.sliceFrom(src.items), Noted.clone$Clone)); + rs.vecSetLen(v, rs.usizeAdd(len, k), 1, (): Noted.Noted => { + return (new Noted.Noted((undefined as unknown) as rs.u8) as unknown) as Noted.Noted; + }); + rs.dropVec(src); + } else if (_30 === 3) { + rs.sliceFillWith(rs.sliceRange(spare, 0, k), (): Noted.Noted => { + return Noted.of$spare_Item(n); + }); + rs.vecSetLen(v, rs.usizeAdd(len, k), 1, (): Noted.Noted => { + return (new Noted.Noted((undefined as unknown) as rs.u8) as unknown) as Noted.Noted; + }); + } else if (_30 === 4) { + const _95: Noted.Noted | rs.None = rs.sliceFirst(spare, rs.None); + if (_95 !== rs.None) { + rs.ptrWrite(_95, Noted.of$spare_Item(~n & 0xff)); + Noted.put$spare_Item(_95, out); + _95[Symbol.dispose](); + } + const _105: Noted.Noted | rs.None = rs.sliceFirst(rs.vecSpare(v, 1, (): Noted.Noted => { + return (new Noted.Noted((undefined as unknown) as rs.u8) as unknown) as Noted.Noted; + }), rs.None); + if (_105 !== rs.None) { + rs.ptrWrite(_105, Noted.of$spare_Item(n)); + let swapped: rs.Vec = new rs.Vec(); + swapped = rs.replaceIn(v, swapped); + rs.vecSetLen(swapped, rs.usizeAdd(len, 1), 1, (): Noted.Noted => { + return (new Noted.Noted((undefined as unknown) as rs.u8) as unknown) as Noted.Noted; + }); + const _120: rs.Vec = swapped; + rs.dropVec(v); + v = _120; + } + } else if (!(rs.u8Rem(n, 2) === 0)) { + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1)), rs.drop); + } else { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 1); + } + state$spare_Noted(v, out); + } + rs.dropVec(v); +} + +/** + * A vector of any items written through the slots `spare_capacity_mut` lends: by + * `write`, by assigning one whole, by `write_clone_of_slice` and through the slice it + * gives back, and by `fill_with`, then taken in by `set_len`; one written and read back before + * any `set_len`, and written over by a second call, then taken in by the `Vec` it was + * swapped into; grown and cut. + */ +export function slots$spare_Pair(data: rs.ByteSlice, out: rs.ByteVec): void { + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 16); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const len: rs.usize = v.items.length; + const spare: rs.Slice = rs.vecSpare(v, 16, (): Pair.Pair => { + return ({ a: undefined, b: undefined } as unknown) as Pair.Pair; + }); + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(spare.length, 1)); + const _30: rs.u8 = rs.u8Rem(op, 6); + if (_30 === 0) { + const iter: rs.Iter<[rs.usize, Pair.Pair]> = rs.iterEnumerate(rs.iterSlice(rs.sliceItems(rs.sliceRange(spare, 0, k)))); + while (true) { + const _38: [rs.usize, Pair.Pair] | rs.Done = iter.next(); + if (_38 === rs.DONE) { + break; + } + rs.ptrWrite(_38[1], Pair.of$spare_Item(n ^ (_38[0] & 0xff))); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 16, (): Pair.Pair => { + return ({ a: undefined, b: undefined } as unknown) as Pair.Pair; + }); + } else if (_30 === 1) { + const iter2: rs.Iter<[rs.usize, Pair.Pair]> = rs.iterRev(rs.iterEnumerate(rs.iterSlice(rs.sliceItems(rs.sliceRange(spare, 0, k))))); + while (true) { + const _58: [rs.usize, Pair.Pair] | rs.Done = iter2.next(); + if (_58 === rs.DONE) { + break; + } + Object.assign(_58[1], Pair.of$spare_Item(rs.u8WrappingAdd(n, _58[0] & 0xff))); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 16, (): Pair.Pair => { + return ({ a: undefined, b: undefined } as unknown) as Pair.Pair; + }); + } else if (_30 === 2) { + const src: rs.Vec = rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i3: rs.usize): Pair.Pair => { + return Pair.of$spare_Item(rs.u8WrappingMul(n, i3 & 0xff)); + }), undefined, 16, true); + rs.sliceReverse(rs.sliceWriteCloneOfSlice(rs.sliceRange(spare, 0, k), rs.sliceFrom(src.items), Pair.clone$Clone)); + rs.vecSetLen(v, rs.usizeAdd(len, k), 16, (): Pair.Pair => { + return ({ a: undefined, b: undefined } as unknown) as Pair.Pair; + }); + } else if (_30 === 3) { + rs.sliceFillWith(rs.sliceRange(spare, 0, k), (): Pair.Pair => { + return Pair.of$spare_Item(n); + }); + rs.vecSetLen(v, rs.usizeAdd(len, k), 16, (): Pair.Pair => { + return ({ a: undefined, b: undefined } as unknown) as Pair.Pair; + }); + } else if (_30 === 4) { + const _95: Pair.Pair | rs.None = rs.sliceFirst(spare, rs.None); + if (_95 !== rs.None) { + rs.ptrWrite(_95, Pair.of$spare_Item(~n & 0xff)); + Pair.put$spare_Item(_95, out); + } + const _105: Pair.Pair | rs.None = rs.sliceFirst(rs.vecSpare(v, 16, (): Pair.Pair => { + return ({ a: undefined, b: undefined } as unknown) as Pair.Pair; + }), rs.None); + if (_105 !== rs.None) { + rs.ptrWrite(_105, Pair.of$spare_Item(n)); + let swapped: rs.Vec = new rs.Vec(); + swapped = rs.replaceIn(v, swapped); + rs.vecSetLen(swapped, rs.usizeAdd(len, 1), 16, (): Pair.Pair => { + return ({ a: undefined, b: undefined } as unknown) as Pair.Pair; + }); + v = swapped; + } + } else if (!(rs.u8Rem(n, 2) === 0)) { + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1))); + } else { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 16); + } + state$spare_Pair(v, out); + } +} + +/** + * A vector of any items written through the slots `spare_capacity_mut` lends: by + * `write`, by assigning one whole, by `write_clone_of_slice` and through the slice it + * gives back, and by `fill_with`, then taken in by `set_len`; one written and read back before + * any `set_len`, and written over by a second call, then taken in by the `Vec` it was + * swapped into; grown and cut. + */ +export function slots$tuple2_u8_u32(data: rs.ByteSlice, out: rs.ByteVec): void { + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec<[rs.u8, rs.u32]> = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 8); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const len: rs.usize = v.items.length; + const spare: rs.Slice<[rs.u8, rs.u32]> = rs.vecSpare(v, 8, (): [rs.u8, rs.u32] => { + return ([undefined, undefined] as unknown) as [rs.u8, rs.u32]; + }); + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(spare.length, 1)); + const _30: rs.u8 = rs.u8Rem(op, 6); + if (_30 === 0) { + const iter: rs.Iter<[rs.usize, [rs.u8, rs.u32]]> = rs.iterEnumerate(rs.iterSlice(rs.sliceItems(rs.sliceRange(spare, 0, k)))); + while (true) { + const _38: [rs.usize, [rs.u8, rs.u32]] | rs.Done = iter.next(); + if (_38 === rs.DONE) { + break; + } + rs.ptrWrite(_38[1], copy$tuple2_u8_u32(of$spare_Item_tuple2_u8_u32(n ^ (_38[0] & 0xff)))); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 8, (): [rs.u8, rs.u32] => { + return ([undefined, undefined] as unknown) as [rs.u8, rs.u32]; + }); + } else if (_30 === 1) { + const iter2: rs.Iter<[rs.usize, [rs.u8, rs.u32]]> = rs.iterRev(rs.iterEnumerate(rs.iterSlice(rs.sliceItems(rs.sliceRange(spare, 0, k))))); + while (true) { + const _58: [rs.usize, [rs.u8, rs.u32]] | rs.Done = iter2.next(); + if (_58 === rs.DONE) { + break; + } + Object.assign(_58[1], copy$mem_MaybeUninit_tuple2_u8_u32(copy$tuple2_u8_u32(of$spare_Item_tuple2_u8_u32(rs.u8WrappingAdd(n, _58[0] & 0xff))))); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 8, (): [rs.u8, rs.u32] => { + return ([undefined, undefined] as unknown) as [rs.u8, rs.u32]; + }); + } else if (_30 === 2) { + const src: rs.Vec<[rs.u8, rs.u32]> = rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i3: rs.usize): [rs.u8, rs.u32] => { + return of$spare_Item_tuple2_u8_u32(rs.u8WrappingMul(n, i3 & 0xff)); + }), undefined, 8, true); + rs.sliceReverse(rs.sliceWriteCloneOfSlice(rs.sliceRange(spare, 0, k), rs.sliceFrom(src.items), copy$tuple2_u8_u32)); + rs.vecSetLen(v, rs.usizeAdd(len, k), 8, (): [rs.u8, rs.u32] => { + return ([undefined, undefined] as unknown) as [rs.u8, rs.u32]; + }); + } else if (_30 === 3) { + rs.sliceFillWith(rs.sliceRange(spare, 0, k), (): [rs.u8, rs.u32] => { + return copy$tuple2_u8_u32(of$spare_Item_tuple2_u8_u32(n)); + }); + rs.vecSetLen(v, rs.usizeAdd(len, k), 8, (): [rs.u8, rs.u32] => { + return ([undefined, undefined] as unknown) as [rs.u8, rs.u32]; + }); + } else if (_30 === 4) { + const _95: [rs.u8, rs.u32] | rs.None = rs.sliceFirst(spare, rs.None); + if (_95 !== rs.None) { + rs.ptrWrite(_95, copy$tuple2_u8_u32(of$spare_Item_tuple2_u8_u32(~n & 0xff))); + put$spare_Item_tuple2_u8_u32(_95, out); + } + const _105: [rs.u8, rs.u32] | rs.None = rs.sliceFirst(rs.vecSpare(v, 8, (): [rs.u8, rs.u32] => { + return ([undefined, undefined] as unknown) as [rs.u8, rs.u32]; + }), rs.None); + if (_105 !== rs.None) { + rs.ptrWrite(_105, copy$tuple2_u8_u32(of$spare_Item_tuple2_u8_u32(n))); + let swapped: rs.Vec<[rs.u8, rs.u32]> = new rs.Vec(); + swapped = rs.replaceIn(v, swapped); + rs.vecSetLen(swapped, rs.usizeAdd(len, 1), 8, (): [rs.u8, rs.u32] => { + return ([undefined, undefined] as unknown) as [rs.u8, rs.u32]; + }); + v = swapped; + } + } else if (!(rs.u8Rem(n, 2) === 0)) { + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1))); + } else { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 8); + } + state$tuple2_u8_u32(v, out); + } +} + +/** + * A vector of any items written through the slots `spare_capacity_mut` lends: by + * `write`, by assigning one whole, by `write_clone_of_slice` and through the slice it + * gives back, and by `fill_with`, then taken in by `set_len`; one written and read back before + * any `set_len`, and written over by a second call, then taken in by the `Vec` it was + * swapped into; grown and cut. + */ +export function slots$u32(data: rs.ByteSlice, out: rs.ByteVec): void { + const ops: Ops.Ops = { _0Data: data.data, _0Start: data.start, _0Len: data.length }; + let v: rs.Vec = rs.vecWithCapacity(rs.u8Rem(Ops.byte(ops), 12) as rs.usize, 4); + while (!(ops._0Len === 0)) { + const _13: [rs.u8, rs.u8] = [Ops.byte(ops), Ops.byte(ops)]; + const op: rs.u8 = _13[0]; + const n: rs.u8 = _13[1]; + const len: rs.usize = v.items.length; + const spare: rs.Slice = rs.vecSpare(v, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + const k: rs.usize = rs.usizeRem(n as rs.usize, rs.usizeAdd(spare.length, 1)); + const _30: rs.u8 = rs.u8Rem(op, 6); + if (_30 === 0) { + const iter: rs.Iter<[rs.usize, rs.Place]> = rs.iterEnumerate(rs.iterSliceMut(rs.sliceRange(spare, 0, k))); + while (true) { + const _38: [rs.usize, rs.Place] | rs.Done = iter.next(); + if (_38 === rs.DONE) { + break; + } + _38[1].v = of$spare_Item_u32(n ^ (_38[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + } else if (_30 === 1) { + const iter2: rs.Iter<[rs.usize, rs.Place]> = rs.iterRev(rs.iterEnumerate(rs.iterSliceMut(rs.sliceRange(spare, 0, k)))); + while (true) { + const _58: [rs.usize, rs.Place] | rs.Done = iter2.next(); + if (_58 === rs.DONE) { + break; + } + _58[1].v = of$spare_Item_u32(rs.u8WrappingAdd(n, _58[0] & 0xff)); + } + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + } else if (_30 === 2) { + const src: rs.Vec = rs.iterToVec(rs.iterMap(new rs.Range(0, k), (i3: rs.usize): rs.u32 => { + return of$spare_Item_u32(rs.u8WrappingMul(n, i3 & 0xff)); + }), undefined, 4, true); + rs.sliceReverse(rs.sliceWriteCloneOfSlice(rs.sliceRange(spare, 0, k), rs.sliceFrom(src.items), undefined)); + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + } else if (_30 === 3) { + rs.sliceFillWith(rs.sliceRange(spare, 0, k), (): rs.u32 => { + return of$spare_Item_u32(n); + }); + rs.vecSetLen(v, rs.usizeAdd(len, k), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + } else if (_30 === 4) { + const _95: rs.Place | undefined = rs.sliceFirstMut(spare); + if (_95 !== undefined) { + _95.v = of$spare_Item_u32(~n & 0xff); + put$spare_Item_u32(_95.v, out); + } + const _105: rs.Place | undefined = rs.sliceFirstMut(rs.vecSpare(v, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + })); + if (_105 !== undefined) { + _105.v = of$spare_Item_u32(n); + let swapped: rs.Vec = new rs.Vec(); + swapped = rs.replaceIn(v, swapped); + rs.vecSetLen(swapped, rs.usizeAdd(len, 1), 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + v = swapped; + } + } else if (!(rs.u8Rem(n, 2) === 0)) { + rs.vecTruncate(v, rs.usizeRem(n as rs.usize, rs.usizeAdd(len, 1))); + } else { + rs.vecReserve(v, rs.u8Rem(n, 16) as rs.usize, 4); + } + state$u32(v, out); + } +} + +/** + * Slots never written, copied as they are: within the room, by element and by + * `ptr::copy`, and into a vector of `MaybeUninit`s lengthened over them by `set_len`, + * each written before any read. + */ +export function unwritten(data: rs.ByteSlice, out: rs.ByteVec): void { + const v: rs.Vec = rs.vecWithCapacity(rs.usizeAdd(data.length, 4), 4); + const spare: rs.Slice = rs.vecSpare(v, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + rs.idx(spare, 0); + const _9: rs.u32 = spare.data[spare.start]; + rs.idx(spare, 1); + spare.data[spare.start + 1] = _9; + rs.ptrCopy(rs.sliceAsPtr(spare), rs.ptrAdd(rs.sliceAsPtr(spare), 2), 2); + const iter: rs.Iter<[rs.Place, rs.u8]> = rs.iterZip(rs.iterSliceMut(spare), rs.iterSlice(rs.byteSliceView(data)), [false, false]); + while (true) { + const _27: [rs.Place, rs.u8] | rs.Done = iter.next(); + if (_27 === rs.DONE) { + break; + } + const uninit = _27[0]; + uninit.v = rs.u32Add(_27[1] as rs.u32, 1); + uninit; + } + rs.vecSetLen(v, data.length, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + state$u32(v, out); + const held: rs.Vec = rs.vecWithCapacity(data.length, 2); + rs.vecSetLen(held, data.length, 2, (): rs.u16 => { + return (undefined as unknown) as rs.u16; + }); + rs.sliceReverse(rs.sliceFrom(held.items)); + const iter2: rs.Iter<[rs.usize, rs.Place]> = rs.iterEnumerate(rs.iterSliceMut(rs.sliceFrom(held.items))); + while (true) { + const _55: [rs.usize, rs.Place] | rs.Done = iter2.next(); + if (_55 === rs.DONE) { + break; + } + const i: rs.usize = _55[0]; + rs.idx(data, i); + const uninit2 = _55[1]; + uninit2.v = ((data.data[data.start + i] as rs.u16) << 1) & 0xffff; + uninit2; + } + rs.iterExtendBytes(out, rs.iterFlatMap(rs.iterSlice(held.items), (x: rs.u16): Uint8Array => { + return rs.u16ToBeBytes(x).reverse(); + }, (value: Uint8Array) => rs.iterSlice(value), true, 2), undefined, true); +} + +/** Each kind of item through the pointers and slots of its spare capacity. */ +export function spares(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { + rs.atomicStore(DROPS, 0, 0); + const _8: rs.u8 = rs.u8Rem(kind, 10); + if (_8 === 0) { + pointers$u32(data, out); + } else if (_8 === 1) { + pointers$String(data, out); + } else if (_8 === 2) { + pointers$Option_u16(data, out); + } else if (_8 === 3) { + slots$u32(data, out); + } else if (_8 === 4) { + slots$String(data, out); + } else if (_8 === 5) { + slots$Option_u16(data, out); + } else if (_8 === 6) { + slots$spare_Noted(data, out); + } else if (_8 === 7) { + slots$spare_Pair(data, out); + } else if (_8 === 8) { + slots$tuple2_u8_u32(data, out); + } else { + unwritten(data, out); + } + rs.byteVecPush(out, rs.atomicLoad(DROPS, 0)); +} + +//# sourceMappingURL=spare.ts.map diff --git a/ts/fixtures/lang/elements/src/lib.rs b/ts/fixtures/lang/elements/src/lib.rs index 83d144b42..97d30b9a5 100644 --- a/ts/fixtures/lang/elements/src/lib.rs +++ b/ts/fixtures/lang/elements/src/lib.rs @@ -4,6 +4,7 @@ mod elements; #[path = "../../harness.rs"] pub mod harness; +mod spare; #[cfg(target_arch = "wasm32")] #[path = "../../../wasm.rs"] mod wasm; @@ -23,5 +24,6 @@ fn cases() -> Vec<(&'static str, Case)> { ("elements::edges", |_, data, out| elements::edges(data, out)), ("elements::raw_slices", |_, data, out| elements::raw_slices(data, out)), ("elements::empty_parts", |_, data, out| elements::empty_parts(data, out)), + ("spare::spares", spare::spares), ] } diff --git a/ts/fixtures/lang/elements/src/spare.rs b/ts/fixtures/lang/elements/src/spare.rs new file mode 100644 index 000000000..415b267d0 --- /dev/null +++ b/ts/fixtures/lang/elements/src/spare.rs @@ -0,0 +1,309 @@ +//! A `Vec`'s spare capacity, the room past its length: written through `as_mut_ptr` moved +//! past the length, by element, by `ptr::copy`, and through a slice of the pointers, and +//! through the slots `spare_capacity_mut` lends, then taken in by `set_len`; shortened by +//! `set_len` and read back past its length, as std's `Drain` and `retain` read theirs, then +//! lengthened over what it gave up; and slots never written, copied as they are. Of numbers, +//! `String`s, `Option`s, values that count their drops, and values JS keeps as objects, by +//! a generic function too. + +use std::mem::MaybeUninit; +use std::ptr; +use std::slice; +use std::sync::atomic::{AtomicU8, Ordering}; + +/// What a case's vector holds, made of a byte and put as bytes. +trait Item: Clone { + fn of(n: u8) -> Self; + fn put(&self, out: &mut Vec); +} + +impl Item for u32 { + fn of(n: u8) -> Self { + u32::from(n) * 0x0101 + } + + fn put(&self, out: &mut Vec) { + out.extend_from_slice(&self.to_le_bytes()); + } +} + +impl Item for String { + fn of(n: u8) -> Self { + format!("{n:x}") + } + + fn put(&self, out: &mut Vec) { + out.extend_from_slice(self.as_bytes()); + out.push(0xff); + } +} + +impl Item for Option { + fn of(n: u8) -> Self { + (n % 3 != 0).then_some(u16::from(n) << 4) + } + + fn put(&self, out: &mut Vec) { + out.extend(self.map_or([0xee, 0xee], u16::to_le_bytes)); + } +} + +/// How many `Noted`s dropped since the case began. +static DROPS: AtomicU8 = AtomicU8::new(0); + +/// A value that counts its drops, so what `set_len` gives up shows it drops nothing. JS +/// keeps it as an object, so no pointer into a `Vec` of them is modeled. +#[derive(Clone)] +struct Noted(u8); + +impl Drop for Noted { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::Relaxed); + } +} + +impl Item for Noted { + fn of(n: u8) -> Self { + Noted(n) + } + + fn put(&self, out: &mut Vec) { + out.push(self.0); + } +} + +/// A struct JS keeps as an object. +#[derive(Clone)] +struct Pair { + a: u8, + b: String, +} + +impl Item for Pair { + fn of(n: u8) -> Self { + Pair { a: n, b: n.to_string() } + } + + fn put(&self, out: &mut Vec) { + out.push(self.a); + self.b.put(out); + } +} + +/// A tuple JS keeps as an object. +impl Item for (u8, u32) { + fn of(n: u8) -> Self { + (n, u32::from(n) + 1) + } + + fn put(&self, out: &mut Vec) { + out.push(self.0); + self.1.put(out); + } +} + +/// The bytes a case reads its steps from. +struct Ops<'a>(&'a [u8]); + +impl Ops<'_> { + fn byte(&mut self) -> u8 { + let Some((&b, rest)) = self.0.split_first() else { + return 0; + }; + self.0 = rest; + b + } +} + +/// The length, capacity, and room of `v`, how many `Noted`s dropped, and its items. +fn state(v: &mut Vec, out: &mut Vec) { + for n in [v.len(), v.capacity(), v.spare_capacity_mut().len()] { + out.extend_from_slice(&(n as u32).to_le_bytes()); + } + out.push(DROPS.load(Ordering::Relaxed)); + for x in v.iter() { + x.put(out); + } +} + +/// A vector of values JS copies, written past its length through pointers, by element, by +/// `ptr::copy_nonoverlapping`, and through a slice made of them, and taken in by +/// `set_len`, of the `Vec` itself or of the one it moved to; an insert that moves the tail into the room, as std's does; a removal of a +/// run that shortens it by `set_len` first and reads the run past its length, as std's +/// `Drain` does; a filter that shortens it to nothing and writes back what it keeps, as +/// std's `retain` does; grown, cut, and refilled. +fn pointers(data: &[u8], out: &mut Vec) { + let mut ops = Ops(data); + let mut v: Vec = Vec::with_capacity(usize::from(ops.byte() % 12)); + while !ops.0.is_empty() { + let (op, n) = (ops.byte(), ops.byte()); + let (len, room) = (v.len(), v.capacity() - v.len()); + let k = usize::from(n) % (room + 1); + match op % 8 { + 0 => unsafe { + let end = v.as_mut_ptr().add(len); + for i in 0..k { + end.add(i).write(T::of(n.wrapping_add(i as u8))); + } + // Moved to another binding and back, which keeps its storage, read through + // the pointer from before the move. + let mut moved = std::mem::take(&mut v); + for x in slice::from_raw_parts(end.sub(len), len + k) { + x.put(out); + } + moved.set_len(len + k); + v = moved; + }, + 1 => unsafe { + let src: Vec = (0..k).map(|i| T::of(n ^ i as u8)).collect(); + let src = std::mem::ManuallyDrop::new(src); + ptr::copy_nonoverlapping(src.as_ptr(), v.as_mut_ptr().add(len), k); + v.set_len(len + k); + }, + 2 => unsafe { + let part = slice::from_raw_parts_mut(v.as_mut_ptr().add(len).cast::>(), k); + for (i, slot) in part.iter_mut().enumerate().rev() { + slot.write(T::of(n.wrapping_sub(i as u8))); + } + v.set_len(len + k); + }, + 3 => { + v.reserve(1); + let at = usize::from(n) % (len + 1); + unsafe { + let p = v.as_mut_ptr().add(at); + ptr::copy(p, p.add(1), len - at); + p.write(T::of(n)); + v.set_len(len + 1); + } + } + 4 if len > 0 => { + let at = usize::from(n) % len; + let end = at + usize::from(n >> 4) % (len - at + 1); + unsafe { + v.set_len(at); + let p = v.as_mut_ptr(); + for i in at..end { + ptr::read(p.add(i)).put(out); + } + ptr::copy(p.add(end), p.add(at), len - end); + v.set_len(len - (end - at)); + } + } + 5 => unsafe { + v.set_len(0); + let p = v.as_mut_ptr(); + let mut kept = 0; + for i in 0..len { + let x = ptr::read(p.add(i)); + if (i + usize::from(n)) % 3 != 0 { + p.add(kept).write(x); + kept += 1; + } + } + v.set_len(kept); + }, + 6 => v.reserve(usize::from(n % 16)), + _ => v.truncate(usize::from(n) % (len + 1)), + } + state(&mut v, out); + } +} + +/// A vector of any items written through the slots `spare_capacity_mut` lends: by +/// `write`, by assigning one whole, by `write_clone_of_slice` and through the slice it +/// gives back, and by `fill_with`, then taken in by `set_len`; one written and read back before +/// any `set_len`, and written over by a second call, then taken in by the `Vec` it was +/// swapped into; grown and cut. +fn slots(data: &[u8], out: &mut Vec) { + let mut ops = Ops(data); + let mut v: Vec = Vec::with_capacity(usize::from(ops.byte() % 12)); + while !ops.0.is_empty() { + let (op, n) = (ops.byte(), ops.byte()); + let len = v.len(); + let spare = v.spare_capacity_mut(); + let k = usize::from(n) % (spare.len() + 1); + match op % 6 { + 0 => { + for (i, slot) in spare[..k].iter_mut().enumerate() { + slot.write(T::of(n ^ i as u8)); + } + unsafe { v.set_len(len + k) }; + } + 1 => { + for (i, slot) in spare[..k].iter_mut().enumerate().rev() { + *slot = MaybeUninit::new(T::of(n.wrapping_add(i as u8))); + } + unsafe { v.set_len(len + k) }; + } + 2 => { + let src: Vec = (0..k).map(|i| T::of(n.wrapping_mul(i as u8))).collect(); + spare[..k].write_clone_of_slice(&src).reverse(); + unsafe { v.set_len(len + k) }; + } + 3 => { + spare[..k].fill_with(|| MaybeUninit::new(T::of(n))); + unsafe { v.set_len(len + k) }; + } + 4 => { + if let Some(slot) = spare.first_mut() { + slot.write(T::of(!n)); + unsafe { slot.assume_init_ref() }.put(out); + unsafe { slot.assume_init_drop() }; + } + if let Some(slot) = v.spare_capacity_mut().first_mut() { + slot.write(T::of(n)); + // Swapped out and back, which keeps its storage. + let mut swapped = Vec::new(); + std::mem::swap(&mut v, &mut swapped); + unsafe { swapped.set_len(len + 1) }; + v = swapped; + } + } + _ if n % 2 == 0 => v.reserve(usize::from(n % 16)), + _ => v.truncate(usize::from(n) % (len + 1)), + } + state(&mut v, out); + } +} + +/// Slots never written, copied as they are: within the room, by element and by +/// `ptr::copy`, and into a vector of `MaybeUninit`s lengthened over them by `set_len`, +/// each written before any read. +fn unwritten(data: &[u8], out: &mut Vec) { + let mut v: Vec = Vec::with_capacity(data.len() + 4); + let spare = v.spare_capacity_mut(); + spare[1] = spare[0]; + unsafe { ptr::copy(spare.as_ptr(), spare.as_mut_ptr().add(2), 2) }; + for (slot, &b) in spare.iter_mut().zip(data) { + slot.write(u32::from(b) + 1); + } + unsafe { v.set_len(data.len()) }; + state(&mut v, out); + + let mut held: Vec> = Vec::with_capacity(data.len()); + unsafe { held.set_len(data.len()) }; + held.reverse(); + for (i, slot) in held.iter_mut().enumerate() { + slot.write(u16::from(data[i]) << 1); + } + out.extend(held.iter().flat_map(|x| unsafe { x.assume_init() }.to_le_bytes())); +} + +/// Each kind of item through the pointers and slots of its spare capacity. +pub fn spares(kind: u8, data: &[u8], out: &mut Vec) { + DROPS.store(0, Ordering::Relaxed); + match kind % 10 { + 0 => pointers::(data, out), + 1 => pointers::(data, out), + 2 => pointers::>(data, out), + 3 => slots::(data, out), + 4 => slots::(data, out), + 5 => slots::>(data, out), + 6 => slots::(data, out), + 7 => slots::(data, out), + 8 => slots::<(u8, u32)>(data, out), + _ => unwritten(data, out), + } + out.push(DROPS.load(Ordering::Relaxed)); +} diff --git a/ts/fixtures/lang/panics/hook/expected/hooked.ts b/ts/fixtures/lang/panics/hook/expected/hooked.ts index e8626d09a..7e835f1da 100644 --- a/ts/fixtures/lang/panics/hook/expected/hooked.ts +++ b/ts/fixtures/lang/panics/hook/expected/hooked.ts @@ -388,8 +388,8 @@ export function sited(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { } else if (k === 31) { const _251: rs.VecDeque = rs.dequeClone(deque); const _253: rs.RangeFrom = new rs.RangeFrom(rs.usizeAdd(at, 3, { file: "fixtures/lang/panics/src/hooked.rs", line: 271, col: 50 }), rs.usizeStep); - rs.iterExtendBytes(out, rs.iterMap(rs.dequeRangeMut(_251, _253, { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/vec_deque/mod.rs", line: 1845, col: 36 }), (v5: rs.Place): rs.u8 => { - return v5.v; + rs.iterExtendBytes(out, rs.iterMap(rs.dequeRangeMut(_251, _253, { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/vec_deque/mod.rs", line: 1845, col: 36 }), (v6: rs.Place): rs.u8 => { + return v6.v; }), undefined, true); } else if (k === 32) { const cell2: rs.RefCell = new rs.RefCell(rs.byteVecFrom(Uint8Array.of(n))); @@ -400,8 +400,8 @@ export function sited(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { ((cell4: rs.RefCell): undefined => { rs.refCellBorrow(cell4, { file: "fixtures/lang/panics/src/hooked.rs", line: 278, col: 54 }); })(SHARED.get()); - rs.localKeyWithBorrowMutPlace(SHARED, (v4: rs.Place): undefined => { - v4.v = n; + rs.localKeyWithBorrowMutPlace(SHARED, (v5: rs.Place): undefined => { + v5.v = n; }, { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/std/src/thread/local.rs", line: 721, col: 38 }); } else if (k === 34) { ((cell3: rs.RefCell): undefined => { @@ -476,21 +476,30 @@ export function sited(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { return c & 0xff; }), undefined, true); } else if (k === 68) { - const v2: rs.ByteVec = rs.byteVecWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 324, col: 50 })); - rs.byteVecSetLen(v2, rs.usizeAdd(v2.data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 326, col: 32 })); - rs.byteVecPush(out, v2.length & 0xff); + if (!(rs.u8Rem(n, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 323, col: 15 }) === 0)) { + const v3: rs.Vec = rs.vecWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 330, col: 51 }), 4); + const _442: rs.usize = rs.usizeAdd(rs.vecCapacity(v3, 4), 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 332, col: 32 }); + rs.vecSetLen(v3, _442, 4, (): rs.u32 => { + return (undefined as unknown) as rs.u32; + }); + rs.byteVecPush(out, v3.items.length & 0xff); + } else { + const v2: rs.ByteVec = rs.byteVecWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 324, col: 50 })); + rs.byteVecSetLen(v2, rs.usizeAdd(v2.data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 326, col: 32 })); + rs.byteVecPush(out, v2.length & 0xff); + } } else if (k === 69) { - const _435: rs.ByteSlice = rs.byteSliceFrom(rs.bytes(2).fill((0 as unknown) as rs.u8)); - const part2 = rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 329, col: 81 }); - rs.byteSliceCopyFromSlice(_435, rs.byteSliceRange(rs.byteVecSlice(v), 0, part2, { file: "fixtures/lang/panics/src/hooked.rs", line: 329, col: 78 }), { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/mem/maybe_uninit.rs", line: 1170, col: 14 }); + const _451: rs.ByteSlice = rs.byteSliceFrom(rs.bytes(2).fill((0 as unknown) as rs.u8)); + const part2 = rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 335, col: 81 }); + rs.byteSliceCopyFromSlice(_451, rs.byteSliceRange(rs.byteVecSlice(v), 0, part2, { file: "fixtures/lang/panics/src/hooked.rs", line: 335, col: 78 }), { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/mem/maybe_uninit.rs", line: 1170, col: 14 }); } else if (k === 70) { rs.sliceWriteCloneOfSlice(rs.sliceFrom(Array.from({ length: 2 }, (): rs.String => { return (undefined as unknown) as rs.String; - })), rs.sliceRange(rs.sliceFrom([rs.stringNew()]), 0, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 330, col: 106 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 330, col: 103 }), (a0: rs.String): rs.String => { + })), rs.sliceRange(rs.sliceFrom([rs.stringNew()]), 0, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 336, col: 106 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 336, col: 103 }), (a0: rs.String): rs.String => { return rs.stringClone(a0); }, { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/mem/maybe_uninit.rs", line: 1230, col: 9 }); } else if (k === 71) { - rs.byteVecPush(out, rs.sliceNewUninit(rs.usizeSub(4294967295, at, { file: "fixtures/lang/panics/src/hooked.rs", line: 331, col: 55 }), 2, (): rs.u16 => { + rs.byteVecPush(out, rs.sliceNewUninit(rs.usizeSub(4294967295, at, { file: "fixtures/lang/panics/src/hooked.rs", line: 337, col: 55 }), 2, (): rs.u16 => { return (undefined as unknown) as rs.u16; }).length & 0xff); } else { @@ -520,16 +529,16 @@ export function joined(kind: rs.u8, n: rs.u8, out: rs.ByteVec): void { let joined!: rs.ByteVec; const big: rs.ByteVec = rs.byteVecOf(n, 1 << 16); const refs: (a0: rs.usize) => rs.Vec = (count: rs.usize): rs.Vec => { - return rs.vecFromElem(rs.byteSliceRange(rs.byteVecSlice(big), 0, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 340, col: 40 }), count, undefined); + return rs.vecFromElem(rs.byteSliceRange(rs.byteVecSlice(big), 0, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 346, col: 40 }), count, undefined); }; if (kind === 0) { - joined = rs.byteSlicesJoin(rs.sliceFrom(refs(rs.usizeAdd(1 << 16, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 342, col: 19 })).items)); + joined = rs.byteSlicesJoin(rs.sliceFrom(refs(rs.usizeAdd(1 << 16, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 348, col: 19 })).items)); } else if (kind === 1) { - joined = rs.byteSlicesJoin(rs.sliceFrom(refs(rs.usizeAdd(1 << 16, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 343, col: 19 })).items), rs.byteSliceFrom(Uint8Array.of(n))); + joined = rs.byteSlicesJoin(rs.sliceFrom(refs(rs.usizeAdd(1 << 16, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 349, col: 19 })).items), rs.byteSliceFrom(Uint8Array.of(n))); } else if (kind === 2) { - joined = rs.byteSlicesJoin(rs.sliceFrom(refs(rs.usizeAdd(1 << 15, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 344, col: 19 })).items)); + joined = rs.byteSlicesJoin(rs.sliceFrom(refs(rs.usizeAdd(1 << 15, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 350, col: 19 })).items)); } else { - joined = rs.iterToByteVec(rs.iterMap(rs.iterSlice(rs.slicesJoin(rs.sliceFrom(rs.vecFromElem(rs.sliceFrom(rs.vecFromElem(n as rs.u16, 1 << 16, undefined).items), rs.usizeAdd(1 << 14, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 347, col: 42 }), undefined).items), 2, rs.sliceFrom([1])).items), (_2: rs.u16): rs.u8 => { + joined = rs.iterToByteVec(rs.iterMap(rs.iterSlice(rs.slicesJoin(rs.sliceFrom(rs.vecFromElem(rs.sliceFrom(rs.vecFromElem(n as rs.u16, 1 << 16, undefined).items), rs.usizeAdd(1 << 14, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 353, col: 42 }), undefined).items), 2, rs.sliceFrom([1])).items), (_2: rs.u16): rs.u8 => { return _2 & 0xff; }), undefined, true); } @@ -552,10 +561,10 @@ export function compared(kind: rs.u8, n: rs.u8): rs.u8 { const _5: [rs.RefCell, rs.RefCell] = [new rs.RefCell(n), new rs.RefCell(rs.u8WrappingAdd(n, 1))]; const a: rs.RefCell = _5[0]; const b: rs.RefCell = _5[1]; - if (!(rs.u8Rem(n, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 359, col: 20 }) === 0)) { - _held = rs.refCellBorrowMut(b, { file: "fixtures/lang/panics/src/hooked.rs", line: 359, col: 59 }); + if (!(rs.u8Rem(n, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 365, col: 20 }) === 0)) { + _held = rs.refCellBorrowMut(b, { file: "fixtures/lang/panics/src/hooked.rs", line: 365, col: 59 }); } else { - _held = rs.refCellBorrowMut(a, { file: "fixtures/lang/panics/src/hooked.rs", line: 359, col: 35 }); + _held = rs.refCellBorrowMut(a, { file: "fixtures/lang/panics/src/hooked.rs", line: 365, col: 35 }); } if (kind === 0) { _0 = rs.refCellBy(rs.same, { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/cell.rs", line: 1482, col: 15 }, { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/cell.rs", line: 1482, col: 34 })(a, b) ? 1 : 0; @@ -602,11 +611,11 @@ export function stock(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { const at: rs.usize = n as rs.usize; const whole: rs.ByteSlice = rs.bytesFromVec(rs.byteVecOf(n, 4)); b0: { - const k: rs.u8 = rs.u8Rem(kind, 33, { file: "fixtures/lang/panics/src/hooked.rs", line: 401, col: 24 }); + const k: rs.u8 = rs.u8Rem(kind, 33, { file: "fixtures/lang/panics/src/hooked.rs", line: 407, col: 24 }); if (0 <= k) { if (k <= 1) { rs.setHook((info: rs.PanicHookInfo): undefined => { - const at2: rs.Location = rs.optionUnwrap(info.location, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 403, col: 38 }); + const at2: rs.Location = rs.optionUnwrap(info.location, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 409, col: 38 }); const _10: string = at2.file; const _126: rs.u32 = at2.line; const _14: rs.u32 = at2.col; @@ -615,16 +624,16 @@ export function stock(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { rs.localKeyWithBorrowMut(NOTE, (note: rs.String): undefined => { rs.stringPushStr(note, line.v); }, { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/std/src/thread/local.rs", line: 721, col: 38 }); - rs.panicFmt(["unread"], { file: "fixtures/lang/panics/src/hooked.rs", line: 406, col: 13 }); + rs.panicFmt(["unread"], { file: "fixtures/lang/panics/src/hooked.rs", line: 412, col: 13 }); }, { capacity: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/raw_vec/mod.rs", line: 29, col: 5 }, trusted_capacity: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/vec/spec_from_iter_nested.rs", line: 57, col: 18 }, swap_remove: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/vec/mod.rs", line: 2178, col: 13 }, vec_set_len: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/vec/mod.rs", line: 2138, col: 9 }, into_flattened: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/vec/mod.rs", line: 3667, col: 36 }, rotate_left: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/slice/mod.rs", line: 3902, col: 9 }, rotate_right: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/slice/mod.rs", line: 3948, col: 9 }, ord_violation: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/slice/sort/shared/smallsort.rs", line: 854, col: 5 }, ord_clamp: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/cmp.rs", line: 1166, col: 9 }, f32_clamp: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/num/f32.rs", line: 1665, col: 9 }, f64_clamp: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/num/f64.rs", line: 1643, col: 9 }, encode_utf8: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/char/methods.rs", line: 2507, col: 9 }, encode_utf16: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/char/methods.rs", line: 2601, col: 13 }, format: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/fmt.rs", line: 657, col: 14 }, to_string: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/string.rs", line: 2997, col: 14 }, debug_struct_fields: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/fmt/mod.rs", line: 2572, col: 9 }, exact_len: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/iter/traits/exact_size.rs", line: 122, col: 9 }, join_len: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/str.rs", line: 177, col: 10 }, int_sum: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/iter/traits/accum.rs", line: 206, col: 1 }, int_forward: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/iter/range.rs", line: 554, col: 1 }, char_forward: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/iter/range.rs", line: 119, col: 45 }, hash_capacity: { file: "/cargo/registry/25cdd57fae9f0462/hashbrown-0.17.1/src/raw.rs", line: 36, col: 40 }, btree_range_equal_BTreeSet: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/btree/search.rs", line: 110, col: 21 }, btree_range_equal_BTreeMap: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/btree/search.rs", line: 112, col: 21 }, btree_range_order_BTreeSet: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/btree/search.rs", line: 119, col: 21 }, btree_range_order_BTreeMap: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/btree/search.rs", line: 121, col: 21 }, deque_insert: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/vec_deque/mod.rs", line: 2612, col: 9 }, deque_swap_i: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/vec_deque/mod.rs", line: 1062, col: 9 }, deque_swap_j: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/vec_deque/mod.rs", line: 1063, col: 9 }, deque_rotate_left: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/vec_deque/mod.rs", line: 3198, col: 9 }, deque_rotate_right: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/vec_deque/mod.rs", line: 3243, col: 9 }, deque_split_off: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/vec_deque/mod.rs", line: 2724, col: 9 }, list_split_off: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/alloc/src/collections/linked_list.rs", line: 1015, col: 9 }, mutex_lock: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/std/src/sys/sync/mutex/no_threads.rs", line: 28, col: 9 }, once_force: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/std/src/sync/once.rs", line: 227, col: 20 }, reentrant_init: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/cell/once.rs", line: 325, col: 66 }, lazy_poisoned: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/cell/lazy.rs", line: 386, col: 5 }, ready_poll: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/future/ready.rs", line: 23, col: 35 }, ready_into_inner: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/future/ready.rs", line: 46, col: 16 }, duration_new: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/time.rs", line: 281, col: 18 }, duration_from_mins: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/time.rs", line: 540, col: 13 }, duration_from_hours: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/time.rs", line: 510, col: 13 }, duration_add: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/time.rs", line: 1345, col: 31 }, duration_sub: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/time.rs", line: 1365, col: 31 }, duration_mul: { file: "/rustc/7df81381d027710708209f36b98d11b1c88f8d2e/library/core/src/time.rs", line: 1385, col: 31 }, bytes_advance: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/lib.rs", line: 207, col: 5 }, bytes_does_not_fit: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/lib.rs", line: 215, col: 5 }, bytes_slice: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes.rs", line: 374, col: 28 }, bytes_slice_ref_start: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes.rs", line: 426, col: 9 }, bytes_slice_ref_end: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes.rs", line: 432, col: 9 }, bytes_split_off: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes.rs", line: 481, col: 9 }, bytes_split_to: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes.rs", line: 533, col: 9 }, bytes_buf_advance: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes.rs", line: 694, col: 9 }, bytes_mut_split_off: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes_mut.rs", line: 329, col: 9 }, bytes_mut_split_to: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes_mut.rs", line: 408, col: 9 }, bytes_mut_set_len: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes_mut.rs", line: 545, col: 9 }, bytes_mut_overflow: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes_mut.rs", line: 700, col: 21 }, bytes_mut_overflow_offset: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes_mut.rs", line: 720, col: 29 }, bytes_mut_buf_advance: { file: "/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.12.1/src/bytes_mut.rs", line: 1246, col: 9 } }); const subset: rs.ByteSlice = rs.bytesSlice(whole, 0, 1); if (k === 0) { - const _22: rs.ByteSlice = rs.bytesSlice(whole, rs.usizeAdd(1, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 410, col: 34 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 410, col: 30 })); + const _22: rs.ByteSlice = rs.bytesSlice(whole, rs.usizeAdd(1, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 416, col: 34 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 416, col: 30 })); held = rs.bytesSliceRef(_22, subset); rs.bytesDrop(_22); } else { const _32: rs.ByteSlice = rs.bytesSlice(whole, 0, 1); - const _35: rs.ByteSlice = rs.byteSliceRange(whole, 0, rs.usizeAdd(2, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 411, col: 58 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 411, col: 54 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 411, col: 51 }); + const _35: rs.ByteSlice = rs.byteSliceRange(whole, 0, rs.usizeAdd(2, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 417, col: 58 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 417, col: 54 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 417, col: 51 }); held = rs.bytesSliceRef(_32, _35); rs.bytesDrop(_32); } @@ -636,38 +645,38 @@ export function stock(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { } } hook(); - const shared: rs.BytesMut = rs.bytesMutFrom(rs.byteSliceRange(rs.byteSliceFrom(rs.bytes(8).fill(n)), 0, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 417, col: 44 })); - const _52: rs.u8 = rs.u8Rem(kind, 33, { file: "fixtures/lang/panics/src/hooked.rs", line: 418, col: 11 }); + const shared: rs.BytesMut = rs.bytesMutFrom(rs.byteSliceRange(rs.byteSliceFrom(rs.bytes(8).fill(n)), 0, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 423, col: 44 })); + const _52: rs.u8 = rs.u8Rem(kind, 33, { file: "fixtures/lang/panics/src/hooked.rs", line: 424, col: 11 }); if (_52 === 2) { - const _56: rs.ByteSlice = rs.bytesSlice(whole, rs.usizeAdd(at, 3, { file: "fixtures/lang/panics/src/hooked.rs", line: 419, col: 49 }), 2); + const _56: rs.ByteSlice = rs.bytesSlice(whole, rs.usizeAdd(at, 3, { file: "fixtures/lang/panics/src/hooked.rs", line: 425, col: 49 }), 2); rs.byteVecExtendFromSlice(out, _56); rs.bytesDrop(_56); } else if (_52 === 3) { - const _63: rs.ByteSlice = rs.bytesSlice(whole, 0, rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 420, col: 51 })); + const _63: rs.ByteSlice = rs.bytesSlice(whole, 0, rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 426, col: 51 })); rs.byteVecExtendFromSlice(out, _63); rs.bytesDrop(_63); } else if (_52 === 4) { - const _72: rs.RangeInclusive = new rs.RangeInclusive(rs.usizeSub(4294967295, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 421, col: 62 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 421, col: 49 }), 4294967295, rs.usizeStep); + const _72: rs.RangeInclusive = new rs.RangeInclusive(rs.usizeSub(4294967295, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 427, col: 62 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 427, col: 49 }), 4294967295, rs.usizeStep); const _70: rs.ByteSlice = rs.bytesSliceInclusive(whole, _72); rs.byteVecExtendFromSlice(out, _70); rs.bytesDrop(_70); } else if (_52 === 5) { let _81: rs.ByteSlice = rs.bytesClone(whole); - const _83: rs.usize = rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 422, col: 60 }); + const _83: rs.usize = rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 428, col: 60 }); const _79: rs.ByteSlice = rs.bytesSplitTo(rs.place(() => _81, (value9) => _81 = value9), _83); rs.byteVecExtendFromSlice(out, _79); rs.bytesDrop(_79); rs.bytesDrop(_81); } else if (_52 === 6) { let _89: rs.ByteSlice = rs.bytesClone(whole); - const _91: rs.usize = rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 423, col: 61 }); + const _91: rs.usize = rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 429, col: 61 }); const _87: rs.ByteSlice = rs.bytesSplitOff(rs.place(() => _89, (value8) => _89 = value8), _91); rs.byteVecExtendFromSlice(out, _87); rs.bytesDrop(_87); rs.bytesDrop(_89); } else if (_52 === 7) { let _94: rs.ByteSlice = rs.bytesClone(whole); - const _96: rs.usize = rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 424, col: 36 }); + const _96: rs.usize = rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 430, col: 36 }); rs.bytesAdvance(rs.place(() => _94, (value7) => _94 = value7), _96); rs.bytesDrop(_94); } else if (_52 === 8) { @@ -676,12 +685,12 @@ export function stock(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { rs.bytesDrop(_101); } else if (_52 === 9) { let _107: rs.ByteSlice = rs.bytesClone(whole); - const _109: rs.usize = rs.usizeAdd(9, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 426, col: 50 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 426, col: 46 }); + const _109: rs.usize = rs.usizeAdd(9, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 432, col: 50 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 432, col: 46 }); rs.byteVecPush(out, rs.u64Low(rs.u64FromBeBytes(rs.bytesReadInt(rs.place(() => _107, (value5) => _107 = value5), 8, _109, false, false))) & 0xff); rs.bytesDrop(_107); } else if (_52 === 10) { - let _114: rs.ByteSlice = rs.byteSliceRange(data, 0, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 427, col: 21 }); - const _116: rs.usize = rs.usizeAdd(data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 427, col: 35 }); + let _114: rs.ByteSlice = rs.byteSliceRange(data, 0, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 433, col: 21 }); + const _116: rs.usize = rs.usizeAdd(data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 433, col: 35 }); rs.byteSliceAdvance(rs.place(() => _114, (value4) => _114 = value4), _116); } else if (_52 === 11) { let _120: rs.ByteSlice = rs.bytesClone(whole); @@ -690,75 +699,75 @@ export function stock(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { rs.bytesDrop(_120); } else if (_52 === 12) { let _129: rs.ByteSlice = rs.bytesClone(whole); - const _131: rs.usize = rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 429, col: 66 }); + const _131: rs.usize = rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 435, col: 66 }); const _127: rs.ByteSlice = rs.bytesSplitTo(rs.place(() => _129, (value2) => _129 = value2), _131); rs.byteVecExtendFromSlice(out, _127); rs.bytesDrop(_127); rs.bytesDrop(_129); } else if (_52 === 13) { - let _137: rs.ByteSlice = rs.byteSliceRange(data, 0, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 430, col: 44 }); - const _139: rs.usize = rs.usizeAdd(data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 430, col: 64 }); + let _137: rs.ByteSlice = rs.byteSliceRange(data, 0, undefined, { file: "fixtures/lang/panics/src/hooked.rs", line: 436, col: 44 }); + const _139: rs.usize = rs.usizeAdd(data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 436, col: 64 }); const _135: rs.ByteSlice = rs.byteSliceCopyToBytes(rs.place(() => _137, (value) => _137 = value), _139); rs.byteVecExtendFromSlice(out, _135); rs.bytesDrop(_135); } else if (_52 === 14) { const _146: rs.BytesMut = rs.bytesMutFrom(data); - const _144: rs.BytesMut = rs.bytesMutSplitTo(_146, rs.usizeAdd(data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 431, col: 68 })); + const _144: rs.BytesMut = rs.bytesMutSplitTo(_146, rs.usizeAdd(data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 437, col: 68 })); rs.byteVecExtendFromSlice(out, rs.bytesMutView(_144)); _144[Symbol.dispose](); _146[Symbol.dispose](); } else if (_52 === 15) { const _154: rs.BytesMut = rs.bytesMutWithCapacity(4); - const _152: rs.BytesMut = rs.bytesMutSplitOff(_154, rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 432, col: 75 })); + const _152: rs.BytesMut = rs.bytesMutSplitOff(_154, rs.usizeAdd(at, 5, { file: "fixtures/lang/panics/src/hooked.rs", line: 438, col: 75 })); rs.byteVecExtendFromSlice(out, rs.bytesMutView(_152)); _152[Symbol.dispose](); _154[Symbol.dispose](); } else if (_52 === 16) { - const b: rs.BytesMut = rs.bytesMutWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 434, col: 49 })); - rs.bytesMutSetLen(b, rs.usizeAdd(b.cap, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 436, col: 32 })); + const b: rs.BytesMut = rs.bytesMutWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 440, col: 49 })); + rs.bytesMutSetLen(b, rs.usizeAdd(b.cap, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 442, col: 32 })); rs.byteVecPush(out, b.length & 0xff); b[Symbol.dispose](); } else if (_52 === 17) { - const b2: rs.BytesMut = rs.bytesMutWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 440, col: 49 })); - rs.bytesMutAdvanceMut(b2, rs.usizeAdd(b2.cap, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 442, col: 36 })); + const b2: rs.BytesMut = rs.bytesMutWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 446, col: 49 })); + rs.bytesMutAdvanceMut(b2, rs.usizeAdd(b2.cap, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 448, col: 36 })); rs.byteVecPush(out, b2.length & 0xff); b2[Symbol.dispose](); } else if (_52 === 18) { - const v: rs.ByteVec = rs.byteVecWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 446, col: 50 })); - rs.byteVecAdvanceMut(v, rs.usizeAdd(v.data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 448, col: 36 })); + const v: rs.ByteVec = rs.byteVecWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 452, col: 50 })); + rs.byteVecAdvanceMut(v, rs.usizeAdd(v.data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 454, col: 36 })); rs.byteVecPush(out, v.length & 0xff); } else if (_52 === 19) { const _197: rs.BytesMut = rs.bytesMutFrom(data); - rs.bytesMutAdvance(_197, rs.usizeAdd(data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 451, col: 44 })); + rs.bytesMutAdvance(_197, rs.usizeAdd(data.length, 1, { file: "fixtures/lang/panics/src/hooked.rs", line: 457, col: 44 })); _197[Symbol.dispose](); } else if (_52 === 20) { - const _204: rs.BytesMut = rs.bytesMutFrom(rs.byteSliceRange(data, 0, rs.min(data.length, 3), { file: "fixtures/lang/panics/src/hooked.rs", line: 452, col: 44 })); + const _204: rs.BytesMut = rs.bytesMutFrom(rs.byteSliceRange(data, 0, rs.min(data.length, 3), { file: "fixtures/lang/panics/src/hooked.rs", line: 458, col: 44 })); rs.byteVecPush(out, (rs.bytesMutReadWord(_204, 4, false) as rs.u32) & 0xff); _204[Symbol.dispose](); } else if (_52 === 21) { - const _212: rs.BytesMut = rs.bytesMutWithCapacity(rs.usizeSub(4294967295, at, { file: "fixtures/lang/panics/src/hooked.rs", line: 453, col: 48 })); + const _212: rs.BytesMut = rs.bytesMutWithCapacity(rs.usizeSub(4294967295, at, { file: "fixtures/lang/panics/src/hooked.rs", line: 459, col: 48 })); rs.byteVecPush(out, _212.cap & 0xff); _212[Symbol.dispose](); } else if (_52 === 22) { const _tail: rs.BytesMut = rs.bytesMutSplitOff(shared, 4); - rs.bytesMutReserve(shared, rs.usizeSub(4294967295, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 457, col: 41 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 457, col: 28 })); + rs.bytesMutReserve(shared, rs.usizeSub(4294967295, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 463, col: 41 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 463, col: 28 })); _tail[Symbol.dispose](); } else if (_52 === 23) { rs.bytesMutSplitTo(shared, 4)[Symbol.dispose](); - rs.bytesMutReserve(shared, rs.usizeSub(4294967295 - 4, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 462, col: 45 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 462, col: 28 })); + rs.bytesMutReserve(shared, rs.usizeSub(4294967295 - 4, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 468, col: 45 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 468, col: 28 })); } else if (_52 === 24) { const _235: rs.u64 = n as rs.u64; - const _236: rs.usize = rs.usizeAdd(9, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 464, col: 49 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 464, col: 45 }); + const _236: rs.usize = rs.usizeAdd(9, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 470, col: 49 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 470, col: 45 }); rs.bytesMutPutInt(shared, rs.u64ToBeBytes(_235), _236, false); } else if (_52 === 25) { const _240: rs.i64 = n as rs.i64; - const _241: rs.usize = rs.usizeAdd(9, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 465, col: 45 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 465, col: 41 }); + const _241: rs.usize = rs.usizeAdd(9, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 471, col: 45 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 471, col: 41 }); rs.byteVecPutInt(out, rs.i64ToBeBytes(_240), _241, false); } else if (_52 === 26) { - rs.byteVecPutFill(out, n, rs.usizeSub(4294967295, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 466, col: 53 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 466, col: 40 })); + rs.byteVecPutFill(out, n, rs.usizeSub(4294967295, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 472, col: 53 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 472, col: 40 })); } else if (_52 === 27) { const _253: Take.Take = buf_impl_take$bytes_Buf_bytes_Bytes(rs.bytesClone(whole), 2); - const _251: rs.ByteSlice = Take.copyToBytes$bytes_Buf_bytes_Bytes(_253, rs.usizeAdd(at, 3, { file: "fixtures/lang/panics/src/hooked.rs", line: 467, col: 74 })); + const _251: rs.ByteSlice = Take.copyToBytes$bytes_Buf_bytes_Bytes(_253, rs.usizeAdd(at, 3, { file: "fixtures/lang/panics/src/hooked.rs", line: 473, col: 74 })); rs.byteVecExtendFromSlice(out, _251); rs.bytesDrop(_251); drop$bytes_buf_Take_bytes_Bytes(_253); @@ -768,15 +777,15 @@ export function stock(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { drop$bytes_buf_Take_bytes_Bytes(_261); } else if (_52 === 29) { const chunk: rs.ByteSlice = rs.bytesMutChunkMut(shared); - UninitSlice.writeByte(chunk, rs.usizeAdd(UninitSlice.len(chunk), rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 472, col: 44 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 472, col: 30 }), n); + UninitSlice.writeByte(chunk, rs.usizeAdd(UninitSlice.len(chunk), rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 478, col: 44 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 478, col: 30 }), n); } else if (_52 === 30) { - UninitSlice.writeByte(UninitSlice.indexMut$ops_IndexMut_ops_RangeFrom_usize(rs.byteVecChunkMut(rs.byteVecWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 474, col: 40 }))), new rs.RangeFrom(rs.usizeAdd(65, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 474, col: 65 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 474, col: 60 }), rs.usizeStep), { file: "fixtures/lang/panics/src/hooked.rs", line: 474, col: 59 }), 0, n); + UninitSlice.writeByte(UninitSlice.indexMut$ops_IndexMut_ops_RangeFrom_usize(rs.byteVecChunkMut(rs.byteVecWithCapacity(rs.usizeRem(at, 4, { file: "fixtures/lang/panics/src/hooked.rs", line: 480, col: 40 }))), new rs.RangeFrom(rs.usizeAdd(65, rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 480, col: 65 }), { file: "fixtures/lang/panics/src/hooked.rs", line: 480, col: 60 }), rs.usizeStep), { file: "fixtures/lang/panics/src/hooked.rs", line: 480, col: 59 }), 0, n); } else if (_52 === 31) { const _287: rs.BytesMut = rs.bytesMutWithCapacity(0); - UninitSlice.copyFromSlice(UninitSlice.indexMut$ops_IndexMut_ops_RangeTo_usize(rs.bytesMutChunkMut(_287), { end: rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 475, col: 45 }) }, { file: "fixtures/lang/panics/src/hooked.rs", line: 475, col: 42 }), rs.byteSliceFrom(rs.bytes(3).fill(n))); + UninitSlice.copyFromSlice(UninitSlice.indexMut$ops_IndexMut_ops_RangeTo_usize(rs.bytesMutChunkMut(_287), { end: rs.usizeRem(at, 2, { file: "fixtures/lang/panics/src/hooked.rs", line: 481, col: 45 }) }, { file: "fixtures/lang/panics/src/hooked.rs", line: 481, col: 42 }), rs.byteSliceFrom(rs.bytes(3).fill(n))); _287[Symbol.dispose](); } else { - const _297: rs.BytesMut = rs.bytesMutZeroed(rs.usizeSub(4294967295, at, { file: "fixtures/lang/panics/src/hooked.rs", line: 476, col: 40 })); + const _297: rs.BytesMut = rs.bytesMutZeroed(rs.usizeSub(4294967295, at, { file: "fixtures/lang/panics/src/hooked.rs", line: 482, col: 40 })); rs.byteVecPush(out, _297.length & 0xff); _297[Symbol.dispose](); } @@ -792,7 +801,7 @@ export function stock(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { */ export function edition2018Panicked(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { b0: { - if (!(rs.u8Rem(kind, 7, { file: "fixtures/lang/panics/src/hooked.rs", line: 484, col: 8 }) !== 6)) { + if (!(rs.u8Rem(kind, 7, { file: "fixtures/lang/panics/src/hooked.rs", line: 490, col: 8 }) !== 6)) { if (!(option_unwrapOr$1fr498u(rs.byteSliceFirst(data), 0) > 200)) { break b0; } diff --git a/ts/fixtures/lang/panics/src/hooked.rs b/ts/fixtures/lang/panics/src/hooked.rs index 75cce62bd..92adaba61 100644 --- a/ts/fixtures/lang/panics/src/hooked.rs +++ b/ts/fixtures/lang/panics/src/hooked.rs @@ -320,12 +320,18 @@ pub fn sited(kind: u8, data: &[u8], out: &mut Vec) { ), k @ 53..=56 => joined(k - 53, n, out), k @ 57..=67 => out.push(compared(k - 57, n)), - 68 => { + 68 if n % 2 == 0 => { let mut v = Vec::::with_capacity(at % 4); // SAFETY: none, past the capacity: std's check of its precondition aborts. unsafe { v.set_len(v.capacity() + 1) }; out.push(v.len() as u8); } + 68 => { + let mut v = Vec::::with_capacity(at % 4); + // SAFETY: none, past the capacity: std's check of its precondition aborts. + unsafe { v.set_len(v.capacity() + 1) }; + out.push(v.len() as u8); + } 69 => _ = [std::mem::MaybeUninit::uninit(); 2].write_copy_of_slice(&v[..at % 2]), 70 => _ = [const { std::mem::MaybeUninit::uninit() }; 2].write_clone_of_slice(&[String::new()][..at % 2]), 71 => out.push(Box::<[u16]>::new_uninit_slice(usize::MAX - at).len() as u8), diff --git a/ts/fixtures/lang/slices/expected/slices.ts b/ts/fixtures/lang/slices/expected/slices.ts index aa82e6676..ba4a04179 100644 --- a/ts/fixtures/lang/slices/expected/slices.ts +++ b/ts/fixtures/lang/slices/expected/slices.ts @@ -1102,7 +1102,7 @@ export function subslices(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): voi const l: rs.usize = _292[0]; const r: rs.usize = _292[1]; const at: rs.Place = rs.sliceAsPtr(rs.sliceRange(rs.sliceFrom(words.items), l, r)); - rs.byteVecPush(out, rs.ptrOffsetFrom(at, rs.arrayAsPtr(words.items)) & 0xff); + rs.byteVecPush(out, rs.ptrOffsetFrom(at, rs.vecAsPtr(words, 2)) & 0xff); if (l > 0) { rs.byteVecPush(out, rs.ptrAdd(at, -1).v & 0xff); } diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index 35fee5c9d..c771afb18 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -15,7 +15,6 @@ fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec usize { bytes::Buf::copy_to_bytes(&mut Blank::Empty, len).len() } - -/// The room past a vector's length, whose size is its capacity. -pub fn spare(v: &mut Vec) -> usize { - v.spare_capacity_mut().len() -} diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index c7d2b6a5c..31cd373a0 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -9,7 +9,6 @@ roots = [ "alloc::zeroed", "bound_ranges", "buffers::blank_bytes", - "buffers::spare", "clones::cloned_slots", "clones::dropped_slots", "clones::ranked_slots", diff --git a/ts/runtime/rs.ts b/ts/runtime/rs.ts index 145f43216..59f79090d 100644 --- a/ts/runtime/rs.ts +++ b/ts/runtime/rs.ts @@ -441,9 +441,30 @@ export function ptrCopy(src: Place, dst: Place, n: number, copy?: (valu (to.array as unknown as Uint8Array).set(bytes.subarray(from.index, from.index + n), to.index); return; } - const values = Array.from({ length: n }, (_, i) => from.array[from.index + i]); + const values = Array.from({ length: n }, (_, i) => elemGet(from.array, from.index + i)); // Memory nothing wrote yet is copied as it is, which no value's copy can read. - for (let i = 0; i < n; i++) to.array[to.index + i] = copy && values[i] !== undefined ? copy(values[i]) : values[i]; + for (let i = 0; i < n; i++) elemSet(to.array, to.index + i, copy && values[i] !== undefined ? copy(values[i]) : values[i]); +} + +/** Element `i` of `array`, or of the room past it, which `AtIndex.reach` found. */ +function elemGet(array: { [i: number]: T }, i: number): T { + return i < (array as ArrayLike).length ? array[i] : (roomPast(array, i + 1) as Room).get(i); +} + +/** A write of element `i` of `array`, or of the room past it, which `AtIndex.reach` found. */ +function elemSet(array: { [i: number]: T }, i: number, value: T): void { + if (i < (array as ArrayLike).length) array[i] = value; + else (roomPast(array, i + 1) as Room).set(i, value); +} + +/** + * The array a slice of `len` elements from `at` reads, from the same index: `at`'s own, + * or where it runs past it into a `Vec`'s room, a view of both. + */ +function sliceArray(at: AtIndex, len: number): T[] { + const end = at.index + len; + const room = end > (at.array as ArrayLike).length ? roomPast(at.array, end) : undefined; + return room !== undefined ? roomView(room, end) : (at.array as T[]); } /** @@ -462,7 +483,7 @@ export function ptrSlice(p: Place, len: number): Slice { } const at = elemOf(p); at.reach(len); - return new Slice(at.array as T[], at.index, len); + return new Slice(sliceArray(at, len), at.index, len); } /** @@ -836,7 +857,7 @@ export function byteOptionAsSlice(o: number | undefined): ByteSlice { export function sliceOfPlace(p: Place): Slice { const e = elemOf(p); if (!(p instanceof AtIndex)) ONE.add(e.array); - return new Slice(e.array as T[], e.index, 1); + return new Slice(sliceArray(e, 1), e.index, 1); } /** @@ -2227,12 +2248,7 @@ export function byteVecSpare(v: ByteVec): ByteSlice { * one that can't unwind, so it runs the hook, then aborts, as every panic here does. */ export function byteVecSetLen(v: ByteVec, length: number): void { - if (length > v.data.length) { - panic( - "unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity()\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.", - "vec_set_len", - ); - } + if (length > v.data.length) panic(SET_LEN, "vec_set_len"); v.length = length; } @@ -2427,6 +2443,144 @@ export function vecShrinkTo(v: Vec, min: number, size: number): void { vecHold(v, capShrink(v.items.length, vecCapacity(v, size), min)); } +// Spare capacity. A `Vec`'s items are a JS array as long as it is, which a write past its +// end would lengthen, so what Rust keeps past its length is apart, in its `Room`: what a +// write through a pointer from `as_ptr` or `as_mut_ptr`, or through a slot +// `spare_capacity_mut` lends, put there, and what `set_len` gave up, by index, until +// `set_len` takes it in. + +/** + * The room past a `Vec`'s length, up to its capacity: what each slot there holds. It is + * the allocation's, so it follows the items to whichever `rs.Vec` holds them now, as a + * move such as `mem::take` hands them to another. + */ +export class Room { + /** The items, the allocation's array, which its views read before the room. */ + readonly items: T[]; + /** The `Vec` that last held the items, which gives the capacity. */ + v: Vec; + readonly size: number; + readonly slots = new Map(); + /** What a slot holds before any write: a `MaybeUninit` that holds nothing yet. */ + uninit: (() => T) | undefined; + + constructor(v: Vec, size: number) { + this.items = v.items; + this.v = v; + this.size = size; + } + + /** What slot `i` holds, kept so a write into its parts lands there. */ + get(i: number): T { + if (this.slots.has(i)) return this.slots.get(i) as T; + const value = this.uninit?.() as T; + this.slots.set(i, value); + return value; + } + + set(i: number, value: T): void { + this.slots.set(i, value); + } + + /** What slot `i` holds, which leaves the room for the items. */ + take(i: number): T { + const value = this.get(i); + this.slots.delete(i); + return value; + } +} + +/** Each `Vec`'s room, by the items it is past. */ +const ROOMS = /* @__PURE__ */ new WeakMap>(); + +/** `v`'s room, of `size`-byte elements. */ +function roomOf(v: Vec, size: number): Room { + let room = ROOMS.get(v.items) as Room | undefined; + if (room === undefined) { + room = new Room(v, size); + ROOMS.set(v.items, room); + } + room.v = v; + return room; +} + +/** + * The room past `array` that holds its elements up to `end`, if `array` is the items of a + * `Vec` a pointer was taken from: within its capacity while that `Vec` holds them, and + * else unchecked, as the `Vec` they moved to is unknown here. + */ +export function roomPast(array: object, end: number): Room | undefined { + const room = ROOMS.get(array) as Room | undefined; + if (room === undefined || (room.v.items === room.items && end > vecCapacity(room.v, room.size))) return undefined; + return room; +} + +/** The traps of a view of a `Vec`'s storage, its items and then its room, from `start`. */ +class RoomView extends View { + readonly room: Room; + + constructor(room: Room, items: T[], start: number, length: number) { + super(items, start, length); + this.room = room; + } + + override part(start: number, length: number): RoomView { + return new RoomView(this.room, this.s as T[], this.start + start, length); + } + + override item(i: number): T { + return i < (this.s as T[]).length ? this.s[i] : this.room.get(i); + } + + override put(i: number, value: T): void { + if (i < (this.s as T[]).length) this.s[i] = value; + else this.room.set(i, value); + } +} + +/** The first `end` elements of the allocation `room` is past, its items and then itself, as a JS array read and written where they are. */ +function roomView(room: Room, end: number): T[] { + return new Proxy(new Array(end), new RoomView(room, room.items, 0, end)); +} + +/** `Vec::as_ptr` and `as_mut_ptr` of `size`-byte elements: the pointer to its first, which reaches its room. */ +export function vecAsPtr(v: Vec, size: number): Place { + roomOf(v, size); + return new AtIndex(v.items, 0); +} + +/** + * `Vec::spare_capacity_mut` of `size`-byte elements: the slots past its length, each + * holding what `uninit` makes until a write. + */ +export function vecSpare(v: Vec, size: number, uninit: () => T): Slice { + const cap = vecCapacity(v, size); + const room = roomOf(v, size); + room.uninit = uninit; + return new Slice(roomView(room, cap), v.items.length, cap - v.items.length); +} + +/** What std's check of `set_len`'s precondition says. */ +const SET_LEN = "unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity()\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety."; + +/** + * `Vec::set_len` of `size`-byte elements: what it gives up kept in its room, and what it + * takes in from there, a slot never written holding what `uninit` makes. Past the + * capacity it panics, as `byteVecSetLen` does. + */ +export function vecSetLen(v: Vec, length: number, size: number, uninit: () => T): void { + const cap = vecCapacity(v, size); + if (length > cap) panic(SET_LEN, "vec_set_len"); + vecHold(v, cap); + const items = v.items; + if (length === items.length) return; + const room = roomOf(v, size); + room.uninit = uninit; + for (let i = length; i < items.length; i++) room.set(i, items[i]); + for (let i = items.length; i < length; i++) items.push(room.take(i)); + if (length < items.length) items.length = length; +} + /** * `Vec::clone_from` of `src`, and `clone_into` of a byte slice, over `v`: its buffer, grown * as `reserve` grows it if it holds fewer, holding a copy of `src`'s bytes. diff --git a/ts/runtime/rs/collections.ts b/ts/runtime/rs/collections.ts index c79a57b48..f7b226f8f 100644 --- a/ts/runtime/rs/collections.ts +++ b/ts/runtime/rs/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 { Borrowed, ByteSlice, ByteVec, byteVecPush, byteVecReserve, capReserve, capReserveExact, capTryReserve, capTryReserveExact, type CloneFrom, type Debug, debugStructField, debugStructFinishNonExhaustive, Err, type Fmt, fmtDebugStruct, fmtDebugStructFields, fmtDebugTupleFields, fmtIter, fmtList, type FmtResult, fmtSet, fmtTuple, type Formatter, type None, OK, Ok, panic, type Place, type RangeBound, rangeCheck, type Result, searchBy, type Elements, Slice, sliceData, sliceFrom, sliceLength, sliceSort, sliceStart, Vec, vecAppend, vecCapacity, vecCloneFrom, vecFrom, vecHold, vecKeep, vecMax, vecReserve, vecWithCapacity } from "../rs.ts"; +import { Borrowed, ByteSlice, ByteVec, byteVecPush, byteVecReserve, capReserve, capReserveExact, capTryReserve, capTryReserveExact, type CloneFrom, type Debug, debugStructField, debugStructFinishNonExhaustive, Err, type Fmt, fmtDebugStruct, fmtDebugStructFields, fmtDebugTupleFields, fmtIter, fmtList, type FmtResult, fmtSet, fmtTuple, type Formatter, type None, OK, Ok, panic, type Place, type RangeBound, rangeCheck, type Result, type Room, roomPast, searchBy, type Elements, Slice, sliceData, sliceFrom, sliceLength, sliceSort, sliceStart, Vec, vecAppend, vecCapacity, vecCloneFrom, vecFrom, vecHold, vecKeep, vecMax, vecReserve, vecWithCapacity } from "../rs.ts"; import { allocError, CAPACITY_OVERFLOW, type TryReserveError } from "./alloc.ts"; import type { HashKey, Hashing } from "./hash.ts"; import { type Limbs, lt, type u64, type usize } from "./int.ts"; @@ -407,26 +407,30 @@ export class AtIndex implements Place { } get v(): T { - this.reach(1); - return this.array[this.index]; + if (this.index >= 0 && this.index < (this.array as ArrayLike).length) return this.array[this.index]; + return this.room(1).get(this.index); } set v(value: T) { - this.reach(1); - this.array[this.index] = value; + if (this.index >= 0 && this.index < (this.array as ArrayLike).length) this.array[this.index] = value; + else this.room(1).set(this.index, value); } /** * Fails where `n` elements from here run past either end of the array, which JS - * doesn't keep Rust's memory around: a JS array grows by a write past its end, where a - * `Vec`'s length stays until `set_len`, and a shared subslice is a copy, which a - * pointer moved past it would read nothing of. + * doesn't keep Rust's memory around, but into the room of the `Vec` it is the items + * of: a shared subslice is a copy, which a pointer moved past it would read nothing of. */ reach(n: number): void { - const length = (this.array as ArrayLike).length; - if (this.index < 0 || this.index + n > length) { - throw new Error("rust2-ts: a read or write through a pointer past the array JS keeps it in"); - } + if (this.index >= 0 && this.index + n <= (this.array as ArrayLike).length) return; + this.room(n); + } + + /** The room past the array that holds `n` elements from here, which `reach` requires. */ + private room(n: number): Room { + const room = this.index >= 0 ? roomPast(this.array, this.index + n) : undefined; + if (room === undefined) throw new Error("rust2-ts: a read or write through a pointer past the array JS keeps it in"); + return room; } } diff --git a/ts/src/census.rs b/ts/src/census.rs index c274882c5..55d1c8516 100644 --- a/ts/src/census.rs +++ b/ts/src/census.rs @@ -171,7 +171,6 @@ const VERBATIM: &[&str] = &[ "Some", "UpperExp", "Vec::into_flattened", - "Vec::spare_capacity_mut", "Vec::splice", "alloc", "array::from_ref", diff --git a/ts/src/lower/library.rs b/ts/src/lower/library.rs index 0eb096962..ec302b1d9 100644 --- a/ts/src/lower/library.rs +++ b/ts/src/lower/library.rs @@ -2713,12 +2713,25 @@ fn mapping<'tcx>( // The room past a byte vector's length, a slice of its storage. ("Vec", "spare_capacity_mut") if byte(targ(gargs, 0)) => Expr::rs("byteVecSpare", args), ("Vec", "set_len") if byte(targ(gargs, 0)) => Expr::rs("byteVecSetLen", args), - // The room past its length, which no JS array holds. - ("Vec", "spare_capacity_mut") => { - return Some(b.err( - span, - "`Vec::spare_capacity_mut` of other than bytes, whose room past its length no JS array holds, which is not supported yet", - )); + // The room past any other's, which the runtime keeps apart from its items, given + // the size its capacity grows by and what a slot holds before a write. + ("Vec", "spare_capacity_mut" | "set_len") => { + let elem = targ(gargs, 0); + let uninit = Ty::new_maybe_uninit(tcx, elem); + let value = b.t.uninit(uninit, span); + let each = Expr::Arrow( + Vec::new(), + b.t.ty(uninit, span), + vec![StmtKind::Return(Some(value)).at(None)], + ); + let mut values = args; + values.push(super::iter::size_of(b, elem, span)); + values.push(each); + let f = match name.as_str() { + "set_len" => "vecSetLen", + _ => "vecSpare", + }; + Expr::rs(f, values) } // Its elements, which nothing drops. ("Vec", "leak") => { diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index 087e48216..462971d53 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -848,7 +848,8 @@ pub fn call<'tcx>( ("slice", true) => Expr::rs("byteSliceAsPtr", vec![s]), ("Vec", true) => Expr::rs("byteVecAsPtr", vec![s]), ("slice", false) => Expr::rs("sliceAsPtr", vec![s]), - _ => Expr::rs("arrayAsPtr", vec![s.member("items")]), + // A `Vec`'s reaches its room, up to the capacity its size grows. + _ => Expr::rs("vecAsPtr", vec![s, super::iter::size_of(b, elem, span)]), } } ("ptr" | "NonNull", "add" | "sub" | "offset" | "wrapping_add" | "wrapping_sub" | "wrapping_offset") => { diff --git a/ts/tests/pointers.ts b/ts/tests/pointers.ts index 77476adaa..70fd79509 100644 --- a/ts/tests/pointers.ts +++ b/ts/tests/pointers.ts @@ -37,13 +37,33 @@ const shared = rs.ptrByteSlice(lone, 1, true); assert.deepEqual(shared.data, Uint8Array.of(3)); unsure(() => rs.ptrOffsetFrom(rs.byteSliceAsPtr(shared), lone)); -// A write into a `Vec`'s capacity past its length, which a JS array would grow by. +// A write past an array that is no `Vec`'s items, which a JS array would grow by. const vec: number[] = [7]; unsure(() => { rs.ptrAdd(rs.arrayAsPtr(vec), 1).v = 8; }); assert.equal(vec.length, 1); +// A write past a `Vec`'s length lands in its room, but not past its capacity, and the +// room moves with the items to the `Vec` that takes them. +const held = rs.vecFrom([7]); +const end = rs.ptrAdd(rs.vecAsPtr(held, 4), 1); +unsure(() => { + end.v = 8; +}); +rs.vecReserveExact(held, 1, 4); +end.v = 8; +assert.deepEqual(held.items, [7]); +rs.vecSetLen(held, 2, 4, () => 0); +assert.deepEqual(held.items, [7, 8]); +rs.vecReserveExact(held, 4, 4); +rs.ptrAdd(end, 1).v = 9; +const taken = new rs.Vec(held.items, held.cap); +held.items = []; +assert.deepEqual(Array.from(rs.ptrSlice(rs.ptrAdd(end, -1), 3).data.slice(0, 3)), [7, 8, 9]); +rs.vecSetLen(taken, 3, 4, () => 0); +assert.deepEqual(taken.items, [7, 8, 9]); + // Memory from `alloc`, which JS keeps as values once a cast types it: its bytes, typed as // another type of the same size, a pointer past the start of what it holds cast back to // bytes, and one to its values passed as if a block.