Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ generic std gap is planned here even when moq never calls it.
- [Relink without rebuilding](/quest/m3/relink.md) - measure upstream's skip of dependency-only rebuilds on moq's edits once it reaches nightly
- [Unsafe code the translator can model](/quest/m3/ts-unsafe.md) - a dependency using only `unsafe` the translator can model translates from source
- [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 Iterator` and `dyn Error`'s downcasts translate, so a consumer neither rewrites nor binds them
- [Trait objects](/quest/m3/ts-dyn.md) - `dyn Error`'s downcasts, `dyn FusedIterator`, and `Arc<dyn Iterator>` translate, so a consumer neither rewrites nor binds them
- [A trait object in a struct's last field](/quest/m3/ts-dyn-tail.md) - `Rc<RefCell<dyn Trait>>` and the like translate, the last field as the object
- [bytes' Chain as a Buf object](/quest/m3/ts-buf-chain.md) - `Chain::copy_to_bytes` across both halves translates, and with it a `Chain` as a `dyn Buf`
- [A Buf object's size](/quest/m3/ts-dyn-buf-size.md) - a `dyn Buf` object holds only the methods some call dispatches to
Expand Down
7 changes: 3 additions & 4 deletions quest/m3/ts-dyn.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Goal

[rust2-ts](/ts/README.md) translates the trait objects of std's and mapped crates' traits
that moq still refuses (`dyn Iterator`), and `dyn FusedIterator`, behind
that it still refuses, `dyn Error`'s downcasts and `dyn FusedIterator`, behind
any pointer std coerces to one, such as `&mut dyn Debug` and
`Arc<dyn Iterator>`, with Rust's dispatch and drop order, proven by differential tests against native Rust, so a consumer
neither rewrites nor binds them.
Expand All @@ -16,13 +16,12 @@ config, so trait objects move from never to not yet.
- `dyn Debug` and `dyn Display` translate as functions writing their value, behind `&`,
`&mut`, `Box`, `Arc`, and `Rc`, `dyn Future`
as an `rt.Future`, `dyn Any` as the class a downcast checks for, `dyn Fn*` as the
closure itself, and the translated crates' traits as an object with the trait's methods.
Build the rest on those.
closure itself, `dyn Iterator` and its subtraits as an `rt.Iter`, and the translated
crates' traits as an object with the trait's methods. Build the rest on those.
- `dyn Error` translates as an object of `source`, `Debug`, and `Display`. Its downcasts
remain: checking the class of `Error.of$T` as `dyn Any`'s do would miss a value upcast
from the crate's own trait over `Error`, whose object is that trait's class, so a
downcast needs the class of the value's own type, as an upcast to `dyn Any` does.
- `Iterator` can be an `rt.Iter`.
- `bytes::Buf` is an object of its methods, as the crate's own traits are, decided with the
maintainer on 2026-11-02, so it works for any implementor.
- Generic traits and associated types name their arguments in the object's type.
Expand Down
12 changes: 10 additions & 2 deletions ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ crate translation reaches is refused, and so are two versions of one crate it re
| `dyn Error` | an object of its `source`, `fmt$Debug`, and `fmt$Display`: `e.source$Error()` |
| `dyn Any` | an instance of the class its value's type was wrapped in, which a downcast checks for: `a instanceof Any.of$dyns_Square ? a.v : undefined` |
| `dyn Fn`, `dyn FnMut`, `dyn FnOnce` | the closure or function it was made of: `(a0: rt.u8) => rt.u32` |
| `dyn Iterator`, `dyn DoubleEndedIterator`, `dyn ExactSizeIterator` | `rt.Iter<Item>`: `rt.iterDyn` of the iterator it was made of |
| constant | its value, inlined as Rust inlines it, so each use of one holding a cell is a cell of its own; one with no value tree, or holding a cell, read from the memory rustc evaluated |
| `static` | a module's value, named for the static, that every use shares, read from the memory rustc evaluated; one that reads another static or a class is an `rt.LazyCell` of it, made on first use, since that may not be made yet when its module is. A `static mut`, and a pointer in one into memory the translation can't name, fail translation |
| a type that drops | a class with `[Symbol.dispose]`: its `Drop` impl, then its fields |
Expand Down Expand Up @@ -490,10 +491,17 @@ that keeps `Error`'s own. `From` an error into a `Box<dyn Error>`, which `?` con
makes one. Its deprecated `description` and `cause`, and its downcasts, are refused, and so
is `From` a string, which boxes std's own private error type.

A `dyn Iterator`, `dyn DoubleEndedIterator`, or `dyn ExactSizeIterator` behind `&`,
`&mut`, or `Box` is an `rt.Iter` of its items, `rt.iterDyn` of the iterator it was made
of, std's or the crate's own: it reads that iterator by the methods std's vtable holds,
such as `next`, `nth`, and `size_hint`, and folds it by `next`, as std's defaults read a
trait object, so a `count` or `last` of a boxed `Chain` drops its items in the order the
trait object's does. A box drops the iterator it owns.

A trait object of std's
or a mapped crate's trait other than `dyn Debug` and `dyn Display` behind `&`, `&mut`,
`Box`, `Arc`, or `Rc`, `dyn Future`,
`dyn Any`, `dyn Error`, `dyn Buf`, and the function traits, of a generic
`dyn Any`, `dyn Error`, `dyn Buf`, the function traits, and those iterators', of a generic
trait or one with an associated type, of a byte array, or behind any other pointer, such
as a struct's last field, is refused, and so are an upcast to `dyn Any` and
`Any::type_id`.
Expand Down Expand Up @@ -873,7 +881,7 @@ they need.

Byte reinterpretation, pointer addresses, pointer arithmetic on a value JS keeps as an object (other than wrapping arithmetic on a null or dangling pointer), memory from `alloc` other than an array of values JS copies, 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 Error`, `dyn Fn*`, `dyn Buf`, and the translated crates' traits'
`dyn Debug`, `dyn Display`, `dyn Future`, `dyn Any`, `dyn Error`, `dyn Fn*`, `dyn Buf`, `dyn Iterator` and its subtraits, and the translated crates' traits'
behind `&`, `&mut`, `Box`, `Arc`, `Rc`, `Weak`, or `Pin` ([trait objects](/quest/m3/ts-dyn.md)), fail translation. Until they translate, an item that needs one, such as a `Box<dyn Error>` made `From` a string, binds to
hand-written TS ([bindings](#bindings)).

Expand Down
8 changes: 8 additions & 0 deletions ts/fixtures/lang/expected/core/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type * as counts_Twin from "../counts.Twin.ts";
import type * as cycles_Logged from "../cycles.Logged.ts";
import * as defaults_Made from "../defaults.Made.ts";
import type * as dyns_Shape from "../dyns.Shape.ts";
import type * as dyns_Tagged from "../dyns.Tagged.ts";
import * as edits_Named from "../edits.Named.ts";
import type * as Ticked from "../generics.Ticked.ts";
import type * as heap_Fault from "../heap.Fault.ts";
Expand Down Expand Up @@ -349,6 +350,13 @@ export function map$1u07cey(self: cycles_Logged.Logged | undefined, f: (a0: cycl
return f(self);
}

export function map$08a6hpg(self: dyns_Tagged.Tagged | undefined, f: (a0: dyns_Tagged.Tagged) => rt.u8): rt.u8 | undefined {
if (self === undefined) {
return undefined;
}
return f(self);
}

export function map$146awhd(self: Hop.Hop | undefined, f: (a0: Hop.Hop) => [rt.u64, rt.u64]): [rt.u64, rt.u64] | undefined {
if (self === undefined) {
return undefined;
Expand Down
21 changes: 21 additions & 0 deletions ts/fixtures/lang/expected/dyns.Chunks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Generated by rust2-ts. Do not edit.

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

/** Lends its bytes as parts, as moq's transports lend a stream's chunks. */
export type Chunks = { chunks$Chunks: () => rt.Iter<rt.ByteSlice> };

export class of$dyns_Lease {
v: Lease.Lease;

constructor(v: Lease.Lease) {
this.v = v;
}

chunks$Chunks(): rt.Iter<rt.ByteSlice> {
return Lease.chunks$dyns_Chunks(this.v);
}
}

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

import * as rt from "./rt.ts";
import { DROPS } from "./dyns.ts";

/** The crate's own iterator, counting down, which logs 200 as it drops. */
export class Countdown {
_0: rt.u8;

constructor(_0: rt.u8) {
this._0 = _0;
}

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

export function next$iter_Iterator(self: Countdown): rt.u8 | rt.Done {
const _2: rt.u8 | undefined = rt.u8CheckedSub(self._0, 1);
if (_2 !== undefined) {
self._0 = _2;
return self._0;
}
return rt.DONE;
}

export function drop$ops_Drop(_self: Countdown): void {
rt.localKeyWithBorrowMut(DROPS, (d: rt.ByteVec): undefined => {
rt.byteVecPush(d, 200);
});
}

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

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

export interface Lease {
_0: rt.ByteVec;
_1: rt.usize;
}

export function chunks$dyns_Chunks(self: Lease): rt.Iter<rt.ByteSlice> {
return rt.iterDyn(rt.byteSliceChunks(rt.byteVecSlice(self._0), self._1));
}

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

import * as rt from "./rt.ts";
import { DROPS } from "./dyns.ts";

/** Logs its tag as it drops. */
export class Tagged {
_0: rt.u8;

constructor(_0: rt.u8) {
this._0 = _0;
}

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

export function drop$ops_Drop(self: Tagged): void {
rt.localKeyWithBorrowMut(DROPS, (d: rt.ByteVec): undefined => {
rt.byteVecPush(d, self._0);
});
}

//# sourceMappingURL=dyns.Tagged.ts.map
Loading