Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 0 additions & 1 deletion quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ generic std gap is planned here even when moq never calls it.
- [Rc and Arc of a slice](/quest/m3/ts-shared-slices.md) - `Rc<[T]>` and `Arc<[T]>` from a `Vec`, a slice, or an iterator translate
- [The rest of a boxed slice's impls](/quest/m3/ts-boxed-slice-rest.md) - `clone_from`, `AsRef`, `AsMut`, `TryFrom` into a boxed array, and `Box<str>` into bytes translate for boxed slices
- [The rest of a vector's methods](/quest/m3/ts-vec-rest.md) - `append`, `resize`, `split_off`, `try_reserve`, and `Vec::from(VecDeque)` translate
- [Aborts in the differential](/quest/m3/ts-abort-differential.md) - the lang differential compares wasm32's aborts, so an `RwLock` locked again while held is tested
- [A reversed zip's per-pair cost](/quest/m3/ts-zip-rev-overhead.md) - a reversed by-index zip costs per pair what a forward one does, or the gap is explained
- [Whole writes into a lazy cell or thread-local key](/quest/m3/ts-lazy-writes.md) - a whole write through a `&mut` to a `LazyCell`, `LazyLock`, or `LocalKey` keeps its state
- [Type errors at the Rust that made them](/quest/m3/ts-span-precision.md) - a `tsc` error on output names the tail expression or call argument that made it
Expand Down
14 changes: 0 additions & 14 deletions quest/m3/ts-abort-differential.md

This file was deleted.

3 changes: 2 additions & 1 deletion ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ a debug build checks it, so translated code panics where native code would: it n
wraps silently. A panic throws `rt.Panic`, with the message native Rust panics with, and
aborts as wasm32's does: it runs no cleanup, so what the translation held is undefined
after one, as a wasm trap leaves it, and a caller that catches `rt.Panic` must not use it
again.
again. An abort without a panic, as std's for an `RwLock` locked again while held,
throws `rt.Abort`, a `Panic` with std's abort message.

Each integer type is its own type to `tsc`, named as Rust's: `rt.u8` is a `number` with a
type-only brand, so a `u16` where a `u8` goes fails the type check, while a plain
Expand Down
4 changes: 2 additions & 2 deletions ts/bench/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ function measureSize({ route, files }: { route: string; files: Uint8Array<ArrayB
const wasm = new Wasm(await WebAssembly.compile(wasmBytes));
function expected(input: Uint8Array): Uint8Array {
const output = wasm.call(input);
if (output === "panic") throw new Error(`native Rust panics on ${hex(input)}`);
if (!(output instanceof Uint8Array)) throw new Error(`native Rust traps on ${hex(input)}`);
return output;
}
const list = workloads(expected);
Expand Down Expand Up @@ -219,7 +219,7 @@ async function native(): Promise<Engine> {
const taskWasm = new Wasm(await WebAssembly.compile(taskWasmBytes));
const handoff = (input: Uint8Array) => {
const output = taskWasm.call(input);
if (output === "panic") throw new Error(`native Rust panics on ${hex(input)}`);
if (!(output instanceof Uint8Array)) throw new Error(`native Rust traps on ${hex(input)}`);
return output;
};
const timings = [
Expand Down
2 changes: 1 addition & 1 deletion ts/bench/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export async function measure(
const { progress, sampleMs } = options;
const want = workloads.map((workload) => {
const output = wasm.call(workload.input);
if (output === "panic") throw new Error(`${workload.name} ${workload.op} panics in native Rust`);
if (!(output instanceof Uint8Array)) throw new Error(`${workload.name} ${workload.op} traps in native Rust`);
return hex(output);
});
// Each subject's timings, one per body, which every round's worker lists alike.
Expand Down
9 changes: 8 additions & 1 deletion ts/fixtures/lang/caller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,13 @@ const mappedLocks = [[0x04, 0x01, 0x02, 0x86, 0x05, 0x0a, 0x03, 0x02, 0x80, 0x01
Uint8Array.of(op("locks::mapped"), 0, ...bytes),
);

/**
* `locks::relock` with each pick: a mutex locked again while a guard holds it, which
* panics, and a read-write lock read or written again while a guard, mapped or not, holds
* it, which aborts but for a read under a read.
*/
const relocks = Array.from({ length: 16 }, (_, pick) => Uint8Array.of(op("locks::relock"), 0, pick));

/**
* `borrows::tries` scripts: each operation through tried guards, given back beside each
* error, printed, and each borrow again while a tried guard holds the cell, which panics.
Expand Down Expand Up @@ -840,4 +847,4 @@ const capacityCases = [
...Array.from({ length: 8 * 6 }, (_, i) => Uint8Array.of(op("capacity::collects"), i % 8, [0, 1, 2, 5, 9, 23][Math.floor(i / 8)], 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
];

export const cases: Uint8Array[] = [...loops, ...durations, ...ints(), ...utf8, ...floats, ...formats, ...parsed, ...singlesCases, ...singlesFormats, ...singlesParsed, ...dyns, ...cells, ...shared, ...locks, ...guards, ...maps, ...mappedLocks, ...tries, ...mutexMaps, ...printed, ...downgrades, ...leaks, ...rwlocks, ...onces, ...bounds, ...unsafeCells, ...edits, ...subslices, ...consumers, ...closures, ...elements, ...ranges, ...reducers, ...sliceEdits, ...drains, ...iters, ...hinted, ...peekedOthers, ...hints, ...reserves, ...setOps, ...zeros, ...writes, ...floatsMulAdds, ...singlesMulAdds, ...unlikeEqs, ...ownNes, ...rangeFroms, ...compares, ...unlikeCompares, ...rangeMethods, ...wraps(), ...refOrders, ...saturates(), ...methods(), ...separated, ...asciiCases, ...gets, ...capacityCases];
export const cases: Uint8Array[] = [...loops, ...durations, ...ints(), ...utf8, ...floats, ...formats, ...parsed, ...singlesCases, ...singlesFormats, ...singlesParsed, ...dyns, ...cells, ...shared, ...locks, ...guards, ...maps, ...mappedLocks, ...relocks, ...tries, ...mutexMaps, ...printed, ...downgrades, ...leaks, ...rwlocks, ...onces, ...bounds, ...unsafeCells, ...edits, ...subslices, ...consumers, ...closures, ...elements, ...ranges, ...reducers, ...sliceEdits, ...drains, ...iters, ...hinted, ...peekedOthers, ...hints, ...reserves, ...setOps, ...zeros, ...writes, ...floatsMulAdds, ...singlesMulAdds, ...unlikeEqs, ...ownNes, ...rangeFroms, ...compares, ...unlikeCompares, ...rangeMethods, ...wraps(), ...refOrders, ...saturates(), ...methods(), ...separated, ...asciiCases, ...gets, ...capacityCases];
22 changes: 22 additions & 0 deletions ts/fixtures/lang/expected/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,14 @@ export function drop$Result_sync_MappedMutexGuard_u64_sync_MappedMutexGuard_u64(
}
}

export function drop$Result_sync_MappedRwLockReadGuard_u8_sync_RwLockReadGuard_locks_Tally(_1: rt.Result<rt.RefCell<rt.u8>, rt.RefCell<locks_Tally.Tally>>): void {
if (_1.ok) {
rt.refRelease(_1.value);
} else {
rt.refRelease(_1.error);
}
}

export function drop$Result_sync_MappedRwLockWriteGuard_u64_sync_MappedRwLockWriteGuard_u64(_1: rt.Result<rt.RefCell<rt.u64>, rt.RefCell<rt.u64>>): void {
if (_1.ok) {
rt.refMutRelease(_1.value);
Expand Down Expand Up @@ -1006,6 +1014,14 @@ export function drop$Result_sync_MutexGuard_u32_sync_TryLockError_sync_MutexGuar
}
}

export function drop$Result_sync_MutexGuard_u8_sync_TryLockError_sync_MutexGuard_u8(_1: rt.Result<rt.Mutex<rt.u8>, rt.TryLockError<rt.Mutex<rt.u8>>>): void {
if (_1.ok) {
rt.mutexUnlock(_1.value);
} else {
drop$sync_TryLockError_sync_MutexGuard_u8(_1.error);
}
}

export function drop$Result_sync_RwLockReadGuard_array4_u8_sync_TryLockError_sync_RwLockReadGuard_array4_u8(_1: rt.Result<rt.RefCell<Uint8Array>, rt.TryLockError<rt.RefCell<Uint8Array>>>): void {
if (_1.ok) {
rt.refRelease(_1.value);
Expand Down Expand Up @@ -1140,6 +1156,12 @@ export function drop$sync_TryLockError_sync_MutexGuard_u32(_1: rt.TryLockError<r
}
}

export function drop$sync_TryLockError_sync_MutexGuard_u8(_1: rt.TryLockError<rt.Mutex<rt.u8>>): void {
if (_1.tag === "Poisoned") {
rt.mutexUnlock((_1 as { tag: "Poisoned"; _0: rt.Mutex<rt.u8> })._0);
}
}

export function drop$sync_TryLockError_sync_RwLockReadGuard_array4_u8(_1: rt.TryLockError<rt.RefCell<Uint8Array>>): void {
if (_1.tag === "Poisoned") {
rt.refRelease((_1 as { tag: "Poisoned"; _0: rt.RefCell<Uint8Array> })._0);
Expand Down
126 changes: 106 additions & 20 deletions ts/fixtures/lang/expected/locks.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Generated by rust2-ts. Do not edit.

import * as rt from "./rt.ts";
import { drop$Result_Result_sync_MappedMutexGuard_u64_sync_MappedMutexGuard_u64_sync_MutexGuard_locks_Tally, drop$Result_Result_sync_MappedRwLockWriteGuard_u64_sync_MappedRwLockWriteGuard_u64_sync_RwLockWriteGuard_locks_Tally, drop$Result_sync_MutexGuard_array4_u8_sync_TryLockError_sync_MutexGuard_array4_u8, drop$Result_sync_MutexGuard_locks_Tally_sync_TryLockError_sync_MutexGuard_locks_Tally, drop$Result_sync_MutexGuard_u32_sync_TryLockError_sync_MutexGuard_u32, drop$Result_sync_RwLockReadGuard_array4_u8_sync_TryLockError_sync_RwLockReadGuard_array4_u8, drop$Result_sync_RwLockReadGuard_locks_Tally_sync_TryLockError_sync_RwLockReadGuard_locks_Tally, drop$Result_sync_RwLockReadGuard_u32_sync_TryLockError_sync_RwLockReadGuard_u32, drop$Result_sync_RwLockWriteGuard_array4_u8_sync_TryLockError_sync_RwLockWriteGuard_array4_u8, drop$Result_sync_RwLockWriteGuard_locks_Tally_sync_TryLockError_sync_RwLockWriteGuard_locks_Tally, drop$Result_sync_RwLockWriteGuard_u32_sync_TryLockError_sync_RwLockWriteGuard_u32 } from "./lib.ts";
import { drop$Result_Result_sync_MappedMutexGuard_u64_sync_MappedMutexGuard_u64_sync_MutexGuard_locks_Tally, drop$Result_Result_sync_MappedRwLockWriteGuard_u64_sync_MappedRwLockWriteGuard_u64_sync_RwLockWriteGuard_locks_Tally, drop$Result_sync_MappedRwLockReadGuard_u8_sync_RwLockReadGuard_locks_Tally, drop$Result_sync_MutexGuard_array4_u8_sync_TryLockError_sync_MutexGuard_array4_u8, drop$Result_sync_MutexGuard_locks_Tally_sync_TryLockError_sync_MutexGuard_locks_Tally, drop$Result_sync_MutexGuard_u32_sync_TryLockError_sync_MutexGuard_u32, drop$Result_sync_MutexGuard_u8_sync_TryLockError_sync_MutexGuard_u8, drop$Result_sync_RwLockReadGuard_array4_u8_sync_TryLockError_sync_RwLockReadGuard_array4_u8, drop$Result_sync_RwLockReadGuard_locks_Tally_sync_TryLockError_sync_RwLockReadGuard_locks_Tally, drop$Result_sync_RwLockReadGuard_u32_sync_TryLockError_sync_RwLockReadGuard_u32, drop$Result_sync_RwLockWriteGuard_array4_u8_sync_TryLockError_sync_RwLockWriteGuard_array4_u8, drop$Result_sync_RwLockWriteGuard_locks_Tally_sync_TryLockError_sync_RwLockWriteGuard_locks_Tally, drop$Result_sync_RwLockWriteGuard_u32_sync_TryLockError_sync_RwLockWriteGuard_u32 } from "./lib.ts";
import { thenSome$0sf2w1i, thenSome$0d5am30 } from "./core/bool.ts";
import { isSomeAnd$09tpccf, unwrapOr$1iemzn8 as option_unwrapOr$1iemzn8, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr } from "./core/option.ts";
import { unwrapOr$1iemzn8 as option_unwrapOr$1iemzn8, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr } from "./core/option.ts";
import { map$02txiwz as result_map$02txiwz, map$1g6jln5 as result_map$1g6jln5, mapOr$0666x4n as result_mapOr$0666x4n, mapOr$1qkf3ab as result_mapOr$1qkf3ab } from "./core/result.ts";
import * as locks_Lock from "./locks.Lock.ts";
import * as locks_Tally from "./locks.Tally.ts";
Expand Down Expand Up @@ -96,22 +96,110 @@ export function locks(data: rt.ByteSlice, out: rt.ByteVec): void {
shared[Symbol.dispose]();
}

/** Locks a mutex while a guard of it is held, if the first byte is odd, which panics. */
/**
* Locks a lock again while a guard of it is held, as the first byte picks, then once more
* after the guard drops: a mutex, locked or tried, which panics as wasm32's does, or a
* read-write lock read or written through a guard, mapped or not, then read if the low
* bit is clear and otherwise written, which aborts as wasm32's does unless both read.
*/
export function relock(data: rt.ByteSlice, out: rt.ByteVec): void {
const mutex: rt.Mutex<rt.u8> = new rt.Mutex(data.length & 0xff);
const guard: rt.Mutex<rt.u8> = rt.mutexLock(mutex);
rt.byteVecPush(out, guard.value);
if (isSomeAnd$09tpccf(rt.byteSliceFirst(data), (b: rt.u8): boolean => {
return rt.u8Rem(b, 2) === 1;
})) {
const _19: rt.Mutex<rt.u8> = rt.mutexLock(mutex);
rt.byteVecPush(out, _19.value);
rt.mutexUnlock(_19);
const _4: rt.u8 | undefined = rt.byteSliceFirst(data);
if (_4 !== undefined) {
const pick: rt.u8 = _4;
const mutex: rt.Mutex<rt.u8> = new rt.Mutex(pick);
const lock: rt.RefCell<locks_Tally.Tally> = new rt.RefCell({ n: pick as rt.u64, seen: rt.byteVecFrom(Uint8Array.of(pick)) });
const again: (a0: rt.ByteVec) => undefined = (out2: rt.ByteVec): undefined => {
if ((pick & 1) === 0) {
const _93: rt.RefCell<locks_Tally.Tally> = rt.rwLockRead(lock);
rt.byteVecPush(out2, rt.u64Low(_93.value.n) & 0xff);
rt.refRelease(_93);
} else {
const _162: rt.RefCell<locks_Tally.Tally> = rt.rwLockWrite(lock);
rt.byteVecPush(out2, _162.value.seen.length & 0xff);
rt.refMutRelease(_162);
}
};
const _15: rt.u8 = rt.u8Rem(pick >> 1, 8);
if (_15 === 0) {
const guard: rt.Mutex<rt.u8> = rt.mutexLock(mutex);
rt.byteVecPush(out, guard.value);
const _31: rt.Mutex<rt.u8> = rt.mutexLock(mutex);
rt.byteVecPush(out, _31.value);
rt.mutexUnlock(_31);
rt.mutexUnlock(guard);
} else if (_15 === 1) {
const _37: rt.Result<rt.Mutex<rt.u8>, rt.TryLockError<rt.Mutex<rt.u8>>> = rt.mutexTryLock(mutex);
if (_37.ok) {
const guard2: rt.Mutex<rt.u8> = _37.value;
rt.byteVecPush(out, guard2.value);
const _48: rt.Mutex<rt.u8> = rt.mutexLock(mutex);
rt.byteVecPush(out, _48.value);
rt.mutexUnlock(_48);
rt.mutexUnlock(guard2);
} else {
drop$Result_sync_MutexGuard_u8_sync_TryLockError_sync_MutexGuard_u8(_37);
rt.panicFmt(["internal error: entered unreachable code: nothing holds the mutex"]);
}
} else if (_15 === 2) {
const read: rt.RefCell<locks_Tally.Tally> = rt.rwLockRead(lock);
rt.byteVecPush(out, rt.u64Low(read.value.n) & 0xff);
again(out);
rt.refRelease(read);
} else if (_15 === 3) {
const write: rt.RefCell<locks_Tally.Tally> = rt.rwLockWrite(lock);
rt.byteVecPush(out, rt.u64Low(write.value.n) & 0xff);
again(out);
rt.refMutRelease(write);
} else if (_15 === 4) {
const _74: rt.RefCell<locks_Tally.Tally> = rt.rwLockRead(lock);
const seen: rt.RefCell<rt.ByteVec> = rt.refMap(_74, ((t4: locks_Tally.Tally): rt.ByteVec => {
return t4.seen;
})(_74.value));
rt.byteVecPush(out, seen.value.length & 0xff);
again(out);
rt.refRelease(seen);
} else if (_15 === 5) {
const _86: rt.RefCell<locks_Tally.Tally> = rt.rwLockWrite(lock);
const n: rt.RefCell<rt.u64> = rt.refMutMap(_86, ((t3: locks_Tally.Tally): rt.Place<rt.u64> => {
return rt.place(() => t3.n, (value2) => t3.n = value2);
})(_86.value));
rt.byteVecPush(out, rt.u64Low(n.value) & 0xff);
again(out);
rt.refMutRelease(n);
} else if (_15 === 6) {
const _101: rt.RefCell<locks_Tally.Tally> = rt.rwLockRead(lock);
const _100: rt.Result<rt.RefCell<rt.u8>, rt.RefCell<locks_Tally.Tally>> = rt.refFilterMap(_101, ((t2: locks_Tally.Tally): rt.u8 | undefined => {
return rt.byteSliceFirst(rt.byteVecSlice(t2.seen));
})(_101.value));
if (_100.ok) {
const first: rt.RefCell<rt.u8> = _100.value;
const first2: rt.RefCell<rt.u8> = rt.refMap(first, ((b: rt.u8): rt.u8 => {
return b;
})(first.value));
rt.byteVecPush(out, first2.value);
again(out);
rt.refRelease(first2);
} else {
drop$Result_sync_MappedRwLockReadGuard_u8_sync_RwLockReadGuard_locks_Tally(_100);
rt.panicFmt(["internal error: entered unreachable code: seen holds the pick"]);
}
} else {
const _114: rt.RefCell<locks_Tally.Tally> = rt.rwLockWrite(lock);
const n2: rt.RefCell<rt.u64> = rt.refMutMap(_114, ((t: locks_Tally.Tally): rt.Place<rt.u64> => {
return rt.place(() => t.n, (value) => t.n = value);
})(_114.value));
const n3: rt.RefCell<rt.u64> = rt.refMutMap(n2, ((n4: rt.Place<rt.u64>): rt.Place<rt.u64> => {
return n4;
})(rt.valuePlace(n2)));
rt.byteVecPush(out, rt.u64Low(n3.value) & 0xff);
again(out);
rt.refMutRelease(n3);
}
const _130: rt.Mutex<rt.u8> = rt.mutexLock(mutex);
rt.byteVecPush(out, _130.value);
rt.mutexUnlock(_130);
again(out);
}
rt.mutexUnlock(guard);
const _27: rt.Mutex<rt.u8> = rt.mutexLock(mutex);
rt.byteVecPush(out, _27.value);
rt.mutexUnlock(_27);
}

/**
Expand Down Expand Up @@ -213,8 +301,7 @@ export function rwlocks(data: rt.ByteSlice, out: rt.ByteVec): void {
/**
* Each byte an operation on a read-write lock through guards mapped and filtered to its
* parts, its value the operand; each puts what it read through them, what the lock holds
* after they drop, and whether it is still locked. Locking it again while one is held
* aborts on wasm32, with no panic message to compare.
* after they drop, and whether it is still locked.
*/
export function mapped(data: rt.ByteSlice, out: rt.ByteVec): void {
const lock: rt.RefCell<locks_Tally.Tally> = new rt.RefCell(locks_Tally.default$Default());
Expand Down Expand Up @@ -364,8 +451,7 @@ export function mapped(data: rt.ByteSlice, out: rt.ByteVec): void {
/**
* Each byte an operation on mutexes through guards mapped and filtered to parts of their
* values, its value the operand; each puts what it read through them, what the mutex
* holds after they drop, and whether it is still locked. Locking it again while one is
* held aborts on wasm32, with no panic message to compare.
* holds after they drop, and whether it is still locked.
*/
export function mutexMapped(data: rt.ByteSlice, out: rt.ByteVec): void {
const mutex: rt.Mutex<locks_Tally.Tally> = new rt.Mutex(locks_Tally.default$Default());
Expand Down
Loading