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: 1 addition & 0 deletions quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ generic std gap is planned here even when moq never calls it.
- [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
- [Waiting: a slice of one byte behind any &mut](/quest/m3/ts-slice-of-one.md) - `slice::from_mut` and `array::from_mut` of a `&mut u8` translate once a consumer calls them
- [Wakers made from a RawWaker](/quest/m3/ts-raw-waker.md) - `Waker::from_raw` and the rest of the raw waker API translate, each vtable call where std makes it
- [Waiting: a slice object for a mutable part of other values](/quest/m3/ts-slice-object.md) - waits on a moq profile showing the `Proxy` view's traps matter, then decides on an `rt.ByteSlice`-like form
- [Port the workflow guard to kixelated/quest](/quest/m3/quest-workflow-guard.md) - quest's environment guard parses YAML as this repository's does
- [An adaptor of the crate's own iterator held as a value](/quest/m3/ts-own-iter-value.md) - `map` and the other adaptors of a fieldless enum that implements `Iterator`, taken by value, translate
Expand Down
25 changes: 25 additions & 0 deletions quest/m3/ts-raw-waker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# [M] Wakers made from a RawWaker

## Goal

[rust2-ts](/ts/README.md) translates a waker built by hand: `RawWakerVTable::new`,
`RawWaker::new`, `Waker::from_raw`, `Waker::new`, `RawWaker::from` an `Arc` of a `Wake`
impl, and `==` of two vtables. Each clone, wake, and drop calls the vtable's function as
std's does, proven by differential tests against native Rust that log each call.

## Plan

Found while closing the rest of `std::future` and `std::task`. No consumer builds a raw
waker yet; the maintainer plans all of std regardless.

- `rt.Waker` already keys its identity on `data` and `vtable`. A vtable could be a frozen
object of its four functions, and a raw waker a class that calls them, with `data` the
`*const ()` identity a waker's data already is.
- The vtable's functions are `unsafe fn` pointers in a `static`, so this may lean on
[unsafe code the translator can model](/quest/m3/ts-unsafe.md).
- `Debug` of a `Waker`, a `Context`, a `RawWaker`, and a `RawWakerVTable` writes
addresses, which JS has no counterpart of: those stay refused.

## Related

- [Unsafe code the translator can model](/quest/m3/ts-unsafe.md) - the `unsafe fn` pointers a vtable holds
4 changes: 4 additions & 0 deletions ts/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ crate translation reaches is refused, and so are two versions of one crate it re
| `AtomicU32` and the others of `bool` and integers, `AtomicPtr<T>` | `rt.Atomic<T>`, the `rt.Place` of its value; an `atomic::Ordering` is its discriminant, and one an operation can't take panics as std's does. An `AtomicPtr` compares pointers only to what JS keeps as an object or bytes, as raw pointers do |
| `async fn` | a function returning `rt.Future<T>`: a class of its own, its coroutine's state machine |
| async closure | a closure returning the future of each call, with what makes the future of a call that consumes it if it owns a value that drops and `Fn` or `FnMut` call it |
| `Poll<T>`, `Waker`, `Context` | `T \| typeof rt.Pending`; `T \| rt.OuterPending` where `T` can already be pending, as `Poll<Poll<u8>>` can, so `Ready(Pending)` keeps apart from `Pending`; `rt.Waker`, which is also the context, and whose `data` and `vtable` are its identity, which `Waker::data`, `Waker::vtable`, and `will_wake` read |
| `pin!(x)`, `poll_fn(f)`, `future::pending()` | `x`; `rt.PollFn`, which drops `f` with itself; `rt.NEVER` |
| `Poll<T>`, `Waker`, `Context` | `T \| typeof rt.Pending`; `T \| rt.OuterPending` where `T` can already be pending, as `Poll<Poll<u8>>` can, so `Ready(Pending)` keeps apart from `Pending`; `rt.Waker`, which is also the context, and whose `data` and `vtable` are its identity, which `Waker::data`, `Waker::vtable`, and `will_wake` read, and `clone_from` keeps where the waker it has `will_wake` the source |
| `pin!(x)`, `poll_fn(f)`, `future::pending()`, `future::ready(v)` | `x`; `rt.PollFn`, which drops `f` with itself; `rt.NEVER`, which every `Pending` is; `rt.Ready`, whose first poll or `into_inner` takes `v` and a later one panics, and which drops `v` with itself unless one took it |
| `Box::pin(x)`, `dyn Future<Output = T>` | `x`; `rt.Future<T>`: an `async` body or std's future as it is, and another future as an `rt.DynFuture` over its `poll`, which drops it with itself unless borrowed |
| `bytes::Bytes` | `rt.ByteSlice`, as `&[u8]` is: its clones and slices share bytes that never change |
| `bytes::BytesMut` | `rt.BytesMut`: a window of storage, which what it splits off and freezes share without overlapping |
Expand Down Expand Up @@ -457,7 +457,7 @@ A collection keeps Rust's key semantics. A hash map or set keeps a key that is a
number, string, or boolean in a JS `Map`, which compares those as Rust's `Eq` does, and
finds any other key, a 64-bit one past 2^53 included, through its translated `Hash` and
`Eq`; a B-tree orders every key by its translated `Ord`. std's impls are the runtime's: an
`Option` orders `None` first, an `Arc` compares, orders, and hashes as what it holds,
`Option` orders `None` first, an `Option` and a `Poll` hash their variant and then what they hold, an `Arc` compares, orders, and hashes as what it holds,
so a map of `Arc<str>` finds a `&str`, a `Cell` and a `RefCell` compare and order as
what they hold, a `RefCell` borrowing each, a one-time cell compares its `Option`, and
arrays, slices, and vectors, of bytes or of other elements, order by their elements and then their length, and compare and hash alike
Expand Down Expand Up @@ -1005,7 +1005,7 @@ method taking a closure tells it, or its accumulator or what it finds, apart fro
or dropping the closure or passing them to std's iterators outside the crate's own types, or a
drop of the accumulator or what it finds, or whose own `find`, `rfind`, or `is_sorted_by` gives
its closure a reference to a `[u8; N]`,
a pointer's address (`{:p}`), `write!` with a placeholder into
a pointer's address (`{:p}`) and `Debug` of a `Waker` or a `Context`, which writes addresses, `write!` with a placeholder into
the crate's own `fmt::Write`, a `str` pattern other than a
`char`, a `&str`, a predicate behind any references and boxes, or chars, a mutable `str` slice, a copy of a closure that changes
what it captured, `mem::swap`, `replace`, or `take` of a reference's whole pointee,
Expand Down
14 changes: 14 additions & 0 deletions ts/fixtures/lang/futures/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "lang-futures-fixture"
description = "A part of the language rust2-ts translates, exercised against native Rust"
version = "0.0.0"
edition.workspace = true
license.workspace = true
publish = false

[lib]
# The cdylib is the native side of the differential test, built for wasm32.
crate-type = ["lib", "cdylib"]

[lints]
workspace = true
22 changes: 22 additions & 0 deletions ts/fixtures/lang/futures/expected/core/option.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Generated by rust2-ts. Do not edit.

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

export function isSomeAnd$09tpccf(self: rt.u8 | undefined, f: (a0: rt.u8) => boolean): boolean {
if (self === undefined) {
return false;
}
return f(self);
}

export function filter$0v80fk8(self: rt.u8 | undefined, predicate: (a0: rt.u8) => boolean): rt.u8 | undefined {
if (self !== undefined) {
const x: rt.u8 = self;
if (predicate(x)) {
return x;
}
}
return undefined;
}

//# sourceMappingURL=option.ts.map
59 changes: 59 additions & 0 deletions ts/fixtures/lang/futures/expected/core/task/poll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Generated by rust2-ts. Do not edit.

import * as rt from "../../rt.ts";
import type * as Logged from "../../futures.Logged.ts";

export function eq$11qt6c3(self: rt.Poll<rt.u8> | rt.OuterPending, other: rt.Poll<rt.u8> | rt.OuterPending): boolean {
if (!((self !== rt.OuterPending ? 0 : 1) === (other !== rt.OuterPending ? 0 : 1))) {
return false;
}
if (self !== rt.OuterPending) {
if (other !== rt.OuterPending) {
return eq$1h9nnoh(self, other);
}
}
return true;
}

export function eq$1h9nnoh(self: rt.Poll<rt.u8>, other: rt.Poll<rt.u8>): boolean {
if (!((self !== rt.Pending ? 0 : 1) === (other !== rt.Pending ? 0 : 1))) {
return false;
}
if (self !== rt.Pending) {
if (other !== rt.Pending) {
return self === other;
}
}
return true;
}

export function map$0fx224j(self: rt.Poll<rt.u8 | undefined>, f: (a0: rt.u8 | undefined) => rt.u8 | undefined): rt.Poll<rt.u8 | undefined> {
if (self !== rt.Pending) {
return f(self);
}
return rt.Pending;
}

export function isReady$1tqk3za(self: rt.Poll<Logged.Logged>): boolean {
if (self !== rt.Pending) {
return true;
}
return false;
}

export function isReady$1ntq2i8(self: rt.Poll<rt.u8>): boolean {
if (self !== rt.Pending) {
return true;
}
return false;
}

export function isPending$1405yze(self: rt.Poll<Logged.Logged>): boolean {
return !isReady$1tqk3za(self);
}

export function isPending$0vrdvv1(self: rt.Poll<rt.u8>): boolean {
return !isReady$1ntq2i8(self);
}

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

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

/** Counts the wakes through it. */
export interface Count {
_0: rt.Atomic<rt.u8>;
}

export function wake$task_Wake(self: rt.Arc<Count>): void {
rt.atomicFetch(self.value._0, rt.u8WrappingAdd, 1, 0);
self[Symbol.dispose]();
}

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

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

/** A waker a struct holds. */
export class Held {
waker: rt.Waker;

constructor(waker: rt.Waker) {
this.waker = waker;
}

[Symbol.dispose](): void {
this.waker[Symbol.dispose]();
}
}

//# sourceMappingURL=futures.Held.ts.map
14 changes: 14 additions & 0 deletions ts/fixtures/lang/futures/expected/futures.Later.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";

/** The crate's own `IntoFuture`, whose future is std's `Ready`. */
export interface Later {
_0: rt.u8;
}

export function intoFuture$future_IntoFuture(self: Later): rt.Ready<rt.u8> {
return new rt.Ready(rt.u8WrappingAdd(self._0, 1));
}

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

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

/** A byte that writes itself into the log as it drops. */
export class Logged {
_0: rt.u8;
_1: rt.Arc<rt.RefCell<rt.ByteVec>>;

constructor(_0: rt.u8, _1: rt.Arc<rt.RefCell<rt.ByteVec>>) {
this._0 = _0;
this._1 = _1;
}

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

export function drop$ops_Drop(self: Logged): void {
const _5: rt.RefCell<rt.ByteVec> = rt.refCellBorrowMut(self._1.value);
rt.byteVecPush(_5.value, self._0);
rt.refMutRelease(_5);
}

//# sourceMappingURL=futures.Logged.ts.map
Loading