Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
dd2ebf5
chore(quest): claim quest/m3/ts-unsafe.md
kixelated Nov 1, 2026
3bafa03
feat(ts): translate pointers into arrays as rt.AtIndex
kixelated Nov 1, 2026
9988c74
fix(ts): refuse a pointer to an element of an array its variable or h…
kixelated Nov 1, 2026
3548e24
Merge remote-tracking branch 'origin/main' into model-unsafe-operations
kixelated Nov 1, 2026
2d8439e
chore(ts): refresh the lang harness snapshot after merging main
kixelated Nov 1, 2026
f2ed825
fix(ts): keep element pointers exact at wrapped addresses, lone value…
kixelated Nov 1, 2026
ca0d3aa
fix(ts): copy only a shared slice of a lone byte, and keep a lone val…
kixelated Nov 1, 2026
981806c
Merge remote-tracking branch 'origin/main' into model-unsafe-operations
kixelated Nov 1, 2026
505dcde
chore(ts): refresh the lang harness snapshot after merging main
kixelated Nov 1, 2026
c82cad5
Merge remote-tracking branch 'origin/main' into model-unsafe-operations
kixelated Nov 1, 2026
762bbd9
feat(ts): refuse pointers a body shows crossing what JS keeps apart
kixelated Nov 1, 2026
7b65f42
fix(ts): trace slices from raw parts, and type arguments past lifetimes
kixelated Nov 1, 2026
42894ef
chore(ts): refresh the lang snapshot for a shared part's pointers
kixelated Nov 1, 2026
08da9f2
fix(ts): trace only std's pointer functions, copy unwritten memory, a…
kixelated Nov 2, 2026
c7beaa5
chore(ts): refresh the lang snapshot for the pointer fixes
kixelated Nov 2, 2026
41ee462
fix(ts): move null and dangling pointers by address
kixelated Nov 2, 2026
923432e
style(ts): format the dangling cases
kixelated Nov 2, 2026
fadfdfa
chore(ts): refresh the lang snapshot for dangling pointers
kixelated Nov 2, 2026
8a6e1f3
fix(ts): measure equal addresses as none apart
kixelated Nov 2, 2026
16d086b
style(ts): format the equal addresses case
kixelated Nov 2, 2026
19bb6ee
chore(ts): refresh the lang snapshot for equal addresses
kixelated Nov 2, 2026
2726e72
Merge remote-tracking branch 'origin/main' into model-unsafe-operations
kixelated Nov 2, 2026
1fff10c
chore(ts): refresh the snapshots after merging main
kixelated Nov 2, 2026
ffd4087
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe
kixelated Nov 2, 2026
21e4090
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe
kixelated Nov 2, 2026
d6b4f5f
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe
kixelated Nov 2, 2026
f1ff2f4
test(ts): accept wasm32's fma a last place off where the translation …
kixelated Nov 2, 2026
ca5ef08
fix(ts): refuse offset_from across array fields, fail on dangling ele…
kixelated Nov 2, 2026
a4b0bc3
chore(ts): regenerate the reject census after merging main
kixelated Nov 2, 2026
19af103
fix(ts): normalize pointers through mutable parts, keep null and dang…
kixelated Nov 2, 2026
702c5a1
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe
kixelated Nov 2, 2026
c209b23
fix(ts): keep the empty byte slices' sentinels tree-shakeable, regene…
kixelated Nov 2, 2026
b091e2e
fix(ts): keep the pointer an empty slice from no array was made from
kixelated Nov 2, 2026
6e3c854
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe
kixelated Nov 2, 2026
33d0b07
fix(ts): find an empty slice's null pointer, which ?? passes over
kixelated Nov 2, 2026
1c170e3
fix(ts): unsize a raw pointer to an array as the place of its slice, …
kixelated Nov 2, 2026
a15976e
test(ts): read an unsized raw slice pointer through a cast
kixelated Nov 2, 2026
b47bb4c
chore(ts): regenerate the elements snapshot
kixelated Nov 2, 2026
b7e835e
Merge remote-tracking branch 'origin/main' into quest/m3/ts-unsafe
kixelated Nov 2, 2026
f270a35
feat(ts): keep a raw slice pointer as its start and length
kixelated Nov 2, 2026
010d1ad
perf(ts): keep the slice a raw slice pointer's first read makes
kixelated Nov 2, 2026
b71eb2f
fix(ts): fail a raw slice read past an array that shrank
kixelated Nov 2, 2026
2224ffe
fix(ts): read through NonNull::as_mut of a slice
kixelated Nov 2, 2026
bbfa2a4
Merge remote-tracking branch 'origin/main' into t3/3bf18645
kixelated Nov 2, 2026
f3d30f7
Merge remote-tracking branch 'origin/main' into t3/3bf18645
kixelated Nov 2, 2026
4c5c4a7
fix(ts): keep the pointer of an empty slice of a lone byte
kixelated Nov 2, 2026
0c41aa0
quest land: merge tested base
Nov 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ generic std gap is planned here even when moq never calls it.
- [The capacity of a BytesMut](/quest/m3/ts-bytes-capacity.md) - `BytesMut::capacity` and what reads it translate with `bytes`' values
- [Trait objects](/quest/m3/ts-dyn.md) - `dyn Error`, `dyn Iterator`, and `dyn Buf` translate, so a consumer neither rewrites nor binds them
- [Placeholders written to a crate's own fmt::Write](/quest/m3/ts-fmt-calls.md) - `write!` with placeholders into a crate's own writer translates, its `write_str` seeing each call std makes
- [Waiting: drop the lang fixture's mul_add allowance](/quest/m3/ts-fma-allowance.md) - the differential fails on any `mul_add` difference again once wasm32's `fma` rounds exactly
- [Waiting: type-check in process with tsrs](/quest/m3/ts-tsrs.md) - rust2-ts checks bindings through tsrs instead of `tsc` once it is a stable library
- [Drop order in std's folds and iterators](/quest/m3/ts-drop-order.md) - the values that drop still refused in std's consumers, flattens, and collects drop as std's do
- [A slice of one value behind any &mut](/quest/m3/ts-slice-of-one.md) - `slice::from_mut` and `array::from_mut` of a `&mut u8`, or of an object no place names, translate
Expand Down
17 changes: 17 additions & 0 deletions quest/m3/ts-fma-allowance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# [XS] Waiting: drop the lang fixture's mul_add allowance

## Goal

Waits on upstream. wasm32's `fma`, compiler-builtins' generic libm, rounds some
near-ties a last place off
([rust-lang/compiler-builtins#1353](https://github.com/rust-lang/compiler-builtins/issues/1353)),
so the lang fixture's differential accepts a `floats::mul_adds` result where the
translation is the exactly rounded one and native is a last place from it
(`ts/fixtures/lang/fma.ts`).

Once [rust-lang/compiler-builtins#1358](https://github.com/rust-lang/compiler-builtins/pull/1358)
ships in the compiler-builtins that the pinned nightly in `ts/rust-toolchain.toml`
builds, delete `fma.ts` and every use of it: `caller.ts`'s import and `within`'s
call, its copy in `ts/tests/fixtures.rs`'s `lang_differential`, and its test
`ts/tests/fma.ts` with `fma_allowance` in `ts/tests/runtime.rs`, so any difference
fails again, and delete this quest.
25 changes: 21 additions & 4 deletions quest/m3/ts-unsafe.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

[rust2-ts](/ts/README.md) translates the `unsafe` operations it can give exact semantics in
JS, so a dependency using only those translates from source instead of being bound by
hand. What is left: pointers into a slice or `Vec`, `ManuallyDrop`, unions over a type
parameter, and a raw pointer to a value JS copies taken through a reference.
hand. What is left: `ManuallyDrop`, unions over a type parameter, a raw pointer to a
value JS copies taken through a reference, and pointers into an array of values JS keeps
as objects.

## Plan

Expand All @@ -25,15 +26,31 @@ none of its own `unsafe`.
- An `unsafe` operation outside the modeled set is refused with its span, as today.
- Undefined behavior in Rust need not be reproduced, but a translated program never
silently differs from native where Rust's behavior is defined.
- Element pointers, `{ array, index }`, with `add`, `offset`, `offset_from`, and
`slice::from_raw_parts` over them: smallvec, arrayvec, and moq-net's `frame.rs`.
- Element pointers into arrays of values JS copies are `rt.AtIndex`, `{ array, index }`,
which `add`, `offset`, `offset_from`, `ptr::copy`, and `slice::from_raw_parts` act on.
Decided with the maintainer on 2026-11-01: where one body shows a pointer crossing what
JS keeps apart (a value in no array, a copied shared subslice), translation refuses it
with a span; a pointer from elsewhere, such as a field, fails there loudly at run time.
A pointer to an element JS keeps as an object, such as a tuple or the crate's struct, is
that object, which knows no array it is in, so arithmetic on one stays refused:
hashbrown's buckets and kio's `log.rs` reach it. smallvec's pointer arithmetic
translates, but it spills to memory from `alloc::alloc`, which this Plan refuses, so it
translates whole only once the maintainer decides how a typed allocation
(`Layout::array::<T>`, then a cast to `*mut T`) is modeled or that smallvec is mapped.
- Decided with the maintainer on 2026-11-02: a raw slice pointer is `rt.RawSlice`, its
first element's pointer and its length, read through only where Rust reads, and an empty
slice from a pointer into no array keeps that pointer through every part of it.
- `ManuallyDrop<T>` as `T` with its drop skipped, as `MaybeUninit` is: crossbeam-epoch's
`Local` reaches it, though crossbeam's tagged pointers stay refused.
- A union over a type parameter, whose layout has no fixed offsets until an instance
fixes them (smallvec's `SmallVecData`): lay out each instance instead of the identity.
- `&raw const *r` where `r` is a `&T` to a value JS copies or a library object, such as
foldhash's seed and arrayvec's `as_ptr`: the reference is the value, not where it is
kept, so it needs the place the reference came from.
- A `Vec`'s spare capacity written through `as_mut_ptr` and committed by `set_len`:
`set_len` is refused, and a write past the length fails loudly at run time, since the
JS array would grow by it. The spare slots need to live outside the array's length
until `set_len` takes them.
- `UnsafeCell::raw_get`, `from_mut`, and `replace`, refused with their span: none is in
moq's census at the pin.
- A slice's pointer cast to an array's of its length, `*(s as *const [u8] as *const
Expand Down
8 changes: 5 additions & 3 deletions ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ crate translation reaches is refused, and so are two versions of one crate it re
| tuple, `[T; N]`, `&[T]`, `Box<[T]>`, `Vec<T>` | an array; for bytes, `Uint8Array` for `[u8; N]`, `rt.ByteSlice` for `&[u8]`, `&[u8; N]`, and `Box<[u8]>`, and `rt.ByteVec` for `Vec<u8>` |
| `Cow<[T]>` | `rt.Cow<T>`: the `Vec` it owns, or an `rt.Borrowed` holding the slice it borrows; `rt.ByteCow` for bytes, an `rt.ByteVec` or an `rt.ByteSlice` |
| `&T`, `&mut T`, `Box<T>`, `Reverse<T>`, `NonZero<T>` | the value; a `&mut` to a value JS copies, such as a number, an `Option`, a `String`, or a reference, or to an `Arc` or a `Waker`, is an `rt.Place<T>`, which for what a box holds is the place holding the box |
| `*const T`, `*mut T`, `NonNull<T>` | what a `&mut T` is: the object, an `rt.ByteSlice` of a `[u8; N]`'s bytes, which compares by the buffer and offset they are at, or an `rt.Place<T>` to a value JS copies and to a library type such as a `Vec` or an `Arc`; `rt.NULL` for null and `rt.DANGLING` for dangling. A `*const ()` is an identity, such as a waker's data, and `rt.DANGLING_UNIT` when dangling; one to a place of `()` or from a reference to one is refused. A write of a whole object copies into it one object deep, as an assignment through a `&mut` does, 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<T>` | what a `&mut T` is: the object, an `rt.ByteSlice` of a `[u8; N]`'s bytes, which compares by the buffer and offset they are at, or an `rt.Place<T>` 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 `rt.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; `rt.NULL` for null and `rt.DANGLING` for dangling. A `*const ()` is an identity, such as a waker's data, and `rt.DANGLING_UNIT` when dangling; one to a place of `()` or from a reference to one is refused. A write of a whole object copies into it one object deep, as an assignment through a `&mut` does, 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>` | `T`: `undefined` until written, or an object whose parts kept as objects are there, holding `undefined` |
| `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 |
| an iterator | `rt.Iter<Item>`, whose adaptors are runtime functions: `rt.iterMap(rt.iterSlice(v), f)` |
Expand Down Expand Up @@ -844,7 +844,7 @@ they need.

## Not yet

Byte reinterpretation, pointer arithmetic and addresses, raw allocation, and unions whose
Byte reinterpretation, pointer addresses, pointer arithmetic on a value JS keeps as an object (other than wrapping arithmetic on a null or dangling pointer), raw allocation, and unions whose
fields overlap in different types ([unsafe](/quest/m3/ts-unsafe.md)), and trait objects other than
`&dyn Debug`, `&dyn Display`, `dyn Future`, `dyn Any`, `dyn Fn*`, and the translated crates' traits'
behind `&`, `&mut`, `Box`, or `Arc` ([trait objects](/quest/m3/ts-dyn.md)), fail translation. Until they translate, an item that needs one, such as a `dyn Error`, binds to
Expand Down Expand Up @@ -913,7 +913,9 @@ built natively for wasm32 and run beside its translation on the same inputs by
`NonZero`, and raw pointers: a linked list of boxed nodes as `hashlink` keeps one, through a union and a
`MaybeUninit` entry, pointers to locals, fields, and whole structs, those
`UnsafeCell::get` gives, as crossbeam-epoch's own `OnceLock` keeps its collector, and
those a generic type holds to its parameter, at each form a pointer takes, and a
those a generic type holds to its parameter, at each form a pointer takes, pointers
into a `Vec`, an array, a boxed slice, and a `MaybeUninit` array, as `smallvec` and
moq-net's frame segments move and copy through them, and a
generic type's arrays, slices, `Vec`s, and `Cow`s of its parameter at bytes, at
`u16`, and at values that drop. Its
differential test runs through `caller.ts`, a
Expand Down
2 changes: 1 addition & 1 deletion ts/fixtures/crates/dep/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ fn read(bytes: &[u8]) -> u8 {
pub fn last(bytes: &[u8]) -> u8 {
assert!(!bytes.is_empty(), "no last byte");
// SAFETY: it holds a byte.
unsafe { *bytes.as_ptr().add(bytes.len() - 1) }
unsafe { *bytes.as_ptr().byte_add(bytes.len() - 1) }
}

/// What [`tally`] counts with, through trait objects of either crate's types.
Expand Down
3 changes: 1 addition & 2 deletions ts/fixtures/crates/refused.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
unsupported call to `core::slice::<impl [u8]>::as_ptr` at fixtures/crates/dep/src/lib.rs:129:18
unsupported call to `std::ptr::const_ptr::<impl *const u8>::add` at fixtures/crates/dep/src/lib.rs:129:27
unsupported call to `std::ptr::const_ptr::<impl *const u8>::byte_add` at fixtures/crates/dep/src/lib.rs:129:27
4 changes: 3 additions & 1 deletion ts/fixtures/lang/caller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// which nothing translated calls. `differential.ts` runs it beside native Rust's
// `harness::entry`, from the output directory.

import { mulAddsWithin } from "./fma.ts";
import * as Fault from "./fmt.Fault.ts";
import { cases as named, run as harness, op as pick } from "./harness.ts";
import * as rt from "./rt.ts";
Expand Down Expand Up @@ -231,7 +232,7 @@ const mulAdds = (max: number, tiny: number, eps: number, op: number[], bytes: (x
const floatsMulAdds = mulAdds(Number.MAX_VALUE, 5e-324, 2 ** -52, op("floats::mul_adds"), double);
const singlesMulAdds = mulAdds(3.4028234663852886e38, 2 ** -149, 2 ** -23, op("singles::mul_adds"), single);

const [floatsAt, singlesAt] = [pick("floats::floats"), pick("singles::singles")];
const [floatsAt, singlesAt, floatsMulAddsAt] = [pick("floats::floats"), pick("singles::singles"), pick("floats::mul_adds")];

/** How many ULPs from native Rust's each float of `floats`' and `singles`' kind 7 may be, which Rust leaves to libm. */
const ULPS = 2n;
Expand All @@ -240,6 +241,7 @@ export function within(input: Uint8Array, native: Uint8Array, translated: Uint8A
// A first byte of 0xff prints a `Fault`, and picks no case.
if (input[0] === 0xff) return false;
const at = ((input[0] << 8) | input[1]) % count;
if (at === floatsMulAddsAt) return mulAddsWithin(native, translated);
const width = at === floatsAt ? 8 : at === singlesAt ? 4 : 0;
if (width === 0 || input[2] % 10 !== 7 || native.length !== translated.length) return false;
const [a, b] = [native, translated].map((v) => new DataView(v.buffer, v.byteOffset, v.length));
Expand Down
7 changes: 7 additions & 0 deletions ts/fixtures/lang/expected/core/bool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ export function thenSome$1jqdi5p(self: boolean, t: rt.Duration): rt.Duration | u
return t;
}

export function thenSome$03chm1q(self: boolean, t: [rt.u8, rt.u8]): [rt.u8, rt.u8] | undefined {
if (!self) {
return undefined;
}
return t;
}

export function thenSome$0b23a33(self: boolean, t: rt.u16): rt.u16 | undefined {
if (!self) {
return undefined;
Expand Down
21 changes: 14 additions & 7 deletions ts/fixtures/lang/expected/core/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,13 @@ export function map$12l9avg(self: rt.u8 | undefined, f: (a0: rt.u8) => Ticked.Ti
return f(self);
}

export function map$1fmzefe(self: rt.u8 | undefined, f: (a0: rt.u8) => [rt.u8, rt.u8]): [rt.u8, rt.u8] | undefined {
if (self === undefined) {
return undefined;
}
return f(self);
}

export function map$1qp1ym6(self: rt.u8 | undefined, f: (a0: rt.u8) => rt.u32): rt.u32 | undefined {
if (self === undefined) {
return undefined;
Expand Down Expand Up @@ -805,13 +812,6 @@ export function map$1pb5zw8(self: rt.u8 | undefined, f: (a0: rt.u8) => [rt.u16,
return f(self);
}

export function map$1fmzefe(self: rt.u8 | undefined, f: (a0: rt.u8) => [rt.u8, rt.u8]): [rt.u8, rt.u8] | undefined {
if (self === undefined) {
return undefined;
}
return f(self);
}

export function map$1c7zybz(self: rt.u8 | undefined, _: (a0: rt.u8) => rt.u32): rt.u32 | undefined {
if (self === undefined) {
return undefined;
Expand Down Expand Up @@ -1092,6 +1092,13 @@ export function mapOr$1w5qtj7(self: undefined | rt.None, default_: rt.u8, f: (a0
return f(self);
}

export function mapOr$0grxkdu(self: rt.u32[] | undefined, default_: rt.u32, f: (a0: rt.u32[]) => rt.u32): rt.u32 {
if (self === undefined) {
return default_;
}
return f(self);
}

export function mapOr$1giiemz(self: rt.Place<rt.u32> | undefined, default_: rt.u32, f: (a0: rt.Place<rt.u32>) => rt.u32): rt.u32 {
if (self === undefined) {
return default_;
Expand Down
108 changes: 108 additions & 0 deletions ts/fixtures/lang/expected/elements.Inline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Generated by rust2-ts. Do not edit.

import * as rt from "./rt.ts";
import { copy$Option_tuple2_u8_u8, copy$mem_MaybeUninit_array_Option_tuple2_u8_u8 } from "./lib.ts";

/**
* Up to four values kept inline in a `MaybeUninit` array, as `smallvec` keeps them,
* inserted and removed by moving the rest through pointers, and dropped in place.
*/
export class Inline<T> {
len: rt.usize;
items: rt.ArrayOf<T>;

constructor(len: rt.usize, items: rt.ArrayOf<T>) {
this.len = len;
this.items = items;
}
}

export function new$Option_tuple2_u8_u8(): Inline<[rt.u8, rt.u8] | undefined> {
return new Inline(0, copy$mem_MaybeUninit_array_Option_tuple2_u8_u8((new Array(4) as unknown) as Array<[rt.u8, rt.u8] | undefined>));
}

export function new$sync_Arc_u8(): Inline<rt.Arc<rt.u8>> {
return new Inline(0, (new Array(4) as unknown) as rt.Arc<rt.u8>[]);
}

export function ptr$Option_tuple2_u8_u8(self: Inline<[rt.u8, rt.u8] | undefined>): rt.Place<[rt.u8, rt.u8] | undefined> {
return rt.sliceAsPtr(self.items as Array<[rt.u8, rt.u8] | undefined>);
}

export function ptr$sync_Arc_u8(self: Inline<rt.Arc<rt.u8>>): rt.Place<rt.Arc<rt.u8>> {
return rt.sliceAsPtr(self.items as rt.Arc<rt.u8>[]);
}

export function asSlice$Option_tuple2_u8_u8(self: Inline<[rt.u8, rt.u8] | undefined>): Array<[rt.u8, rt.u8] | undefined> {
return rt.ptrSlice(rt.sliceAsPtr(self.items as Array<[rt.u8, rt.u8] | undefined>), self.len);
}

export function asSlice$sync_Arc_u8(self: Inline<rt.Arc<rt.u8>>): rt.Arc<rt.u8>[] {
return rt.ptrSlice(rt.sliceAsPtr(self.items as rt.Arc<rt.u8>[]), self.len);
}

export function insert$Option_tuple2_u8_u8(self: Inline<[rt.u8, rt.u8] | undefined>, at: rt.usize, value: [rt.u8, rt.u8] | undefined): void {
if (self.len < 4) {
if (at <= self.len) {
const len: rt.usize = self.len;
const p: rt.Place<[rt.u8, rt.u8] | undefined> = rt.ptrAdd(ptr$Option_tuple2_u8_u8(self), at);
rt.ptrCopy(p, rt.ptrAdd(p, 1), rt.usizeSub(len, at), copy$Option_tuple2_u8_u8);
p.v = copy$Option_tuple2_u8_u8(value);
self.len = rt.usizeAdd(self.len, 1);
return;
}
}
rt.panic("assertion failed: self.len < 4 && at <= self.len");
}

export function insert$sync_Arc_u8(self: Inline<rt.Arc<rt.u8>>, at: rt.usize, value: rt.Arc<rt.u8>): void {
if (self.len < 4) {
if (at <= self.len) {
const len: rt.usize = self.len;
const p: rt.Place<rt.Arc<rt.u8>> = rt.ptrAdd(ptr$sync_Arc_u8(self), at);
rt.ptrCopy(p, rt.ptrAdd(p, 1), rt.usizeSub(len, at));
p.v = value;
self.len = rt.usizeAdd(self.len, 1);
return;
}
}
rt.panic("assertion failed: self.len < 4 && at <= self.len");
}

export function remove$Option_tuple2_u8_u8(self: Inline<[rt.u8, rt.u8] | undefined>, at: rt.usize): [rt.u8, rt.u8] | undefined {
if (!(at < self.len)) {
rt.panic("assertion failed: at < self.len");
} else {
self.len = rt.usizeSub(self.len, 1);
const len: rt.usize = self.len;
const p: rt.Place<[rt.u8, rt.u8] | undefined> = rt.ptrAdd(ptr$Option_tuple2_u8_u8(self), at);
const value: [rt.u8, rt.u8] | undefined = copy$Option_tuple2_u8_u8(p.v);
rt.ptrCopy(rt.ptrAdd(p, 1), p, rt.usizeSub(len, at), copy$Option_tuple2_u8_u8);
return value;
}
}

export function remove$sync_Arc_u8(self: Inline<rt.Arc<rt.u8>>, at: rt.usize): rt.Arc<rt.u8> {
if (!(at < self.len)) {
rt.panic("assertion failed: at < self.len");
} else {
self.len = rt.usizeSub(self.len, 1);
const len: rt.usize = self.len;
const p: rt.Place<rt.Arc<rt.u8>> = rt.ptrAdd(ptr$sync_Arc_u8(self), at);
const value: rt.Arc<rt.u8> = p.v;
rt.ptrCopy(rt.ptrAdd(p, 1), p, rt.usizeSub(len, at));
return value;
}
}

export function drop$ops_Drop_Option_tuple2_u8_u8(self: Inline<[rt.u8, rt.u8] | undefined>): void {
const len: rt.usize = self.len;
new rt.RawSlice(ptr$Option_tuple2_u8_u8(self), len);
}

export function drop$ops_Drop_sync_Arc_u8(self: Inline<rt.Arc<rt.u8>>): void {
const len: rt.usize = self.len;
rt.dropAll(new rt.RawSlice(ptr$sync_Arc_u8(self), len).deref());
}

//# sourceMappingURL=elements.Inline.ts.map
43 changes: 43 additions & 0 deletions ts/fixtures/lang/expected/elements.Storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Generated by rust2-ts. Do not edit.

import * as rt from "./rt.ts";

export class Storage {
data: rt.Place<rt.u8>;
capacity: rt.usize;

constructor(data: rt.Place<rt.u8>, capacity: rt.usize) {
this.data = data;
this.capacity = capacity;
}

[Symbol.dispose](): void {
drop$ops_Drop(this);
}
}

function new_(capacity: rt.usize): Storage {
const boxed: rt.ByteSlice = rt.byteVecSlice(rt.byteVecOf(0, capacity));
const capacity2: rt.usize = boxed.length;
return new Storage(rt.rawByteSliceOf(boxed).ptr, capacity2);
}

export function write(self: Storage, offset: rt.usize, src: rt.ByteSlice): void {
if (!(rt.usizeAdd(offset, src.length) <= self.capacity)) {
rt.panic("assertion failed: offset + src.len() <= self.capacity");
} else {
rt.ptrCopy(rt.byteSliceAsPtr(src), rt.ptrAdd(self.data, offset), src.length);
}
}

export function read(self: Storage, len: rt.usize): rt.ByteSlice {
return rt.ptrByteSlice(self.data, len, true);
}

export function drop$ops_Drop(self: Storage): void {
new rt.RawSlice(self.data, self.capacity).derefBytes(false);
}

export { new_ as new };

//# sourceMappingURL=elements.Storage.ts.map
Loading