diff --git a/quest/m2/ts-model/README.md b/quest/m2/ts-model/README.md index 0b67acd93..649f79578 100644 --- a/quest/m2/ts-model/README.md +++ b/quest/m2/ts-model/README.md @@ -55,11 +55,22 @@ refuses for good, and smallvec's union over a type parameter and raw parts (10) [unsafe](/quest/m3/ts-unsafe.md), so both need safe `cfg(rust2_ts)` twins or bindings there, as does the `unsafe` slice of `model/frame.rs`'s `Filled`. +Decided with the maintainer on 2026-11-04, from a census at the bumped pin +(moq-dev/rust2#390): the refusals no quest owned became the children below. ✅ arrayvec's +`ArrayString` needs three of them (const generic types, `begin_panic`, `str::as_ptr`), +kept separate since each lands alone; rejected: one quest for `ArrayString`. + ## Required - [Iterators into a crate's own collections](/quest/m2/ts-model/from-iterator.md) - `collect`, `flat_map`, and `flatten` through moq-pattern's `Patterns` - [Bytes from an owner that drops](/quest/m2/ts-model/bytes-owner.md) - `Bytes::from_owner` of a frame's segment - [rangemap](/quest/m2/ts-model/rangemap.md) - B-tree ranges by a borrowed key, and std's iterators in a crate's fields - [Addresses as identity](/quest/m2/ts-model/addresses.md) - `Arc::as_ptr(a) as usize` as a key, which needs a decision +- [Option fields at a unit instance](/quest/m2/ts-model/unit-option-fields.md) - `Idle<()>`'s `Option` field tells `Some(())` from `None` +- [Const generic types](/quest/m2/ts-model/const-generics.md) - `ArrayString` and other types with const parameters +- [panic! in a 2015 or 2018 crate](/quest/m2/ts-model/begin-panic.md) - the `begin_panic` mapping keyed by its defining module +- [A string's bytes through its pointer](/quest/m2/ts-model/str-as-ptr.md) - `str::as_ptr` reads the string's UTF-8 +- [Scheduler hints](/quest/m2/ts-model/scheduler-hints.md) - `thread::yield_now` and `hint::spin_loop` translate to nothing +- [Slices not yet written](/quest/m2/ts-model/uninit-slices.md) - `Box::new_uninit_slice` of a frame's segment Public API: the translator's output for moq-net's model. diff --git a/quest/m2/ts-model/begin-panic.md b/quest/m2/ts-model/begin-panic.md new file mode 100644 index 000000000..deb6f6020 --- /dev/null +++ b/quest/m2/ts-model/begin-panic.md @@ -0,0 +1,15 @@ +# [XS] panic! in a 2015 or 2018 crate + +## Goal + +[rust2-ts](/ts/README.md) translates `panic!("literal")` in a 2015 or 2018 edition crate, +which expands to `std::rt::begin_panic`, as it does in 2021, proven by a 2018-edition +panics fixture against native Rust. Today arrayvec's is refused. + +## Plan + +The mapping is keyed by `("rt", "begin_panic")`, but `library::key` builds keys from the +defining module, and std defines `begin_panic` in `std::panicking` and only re-exports it +from `rt`, so the mapping never matches. No fixture used a pre-2021 `panic!`. + +Public API: the translator's output. diff --git a/quest/m2/ts-model/const-generics.md b/quest/m2/ts-model/const-generics.md new file mode 100644 index 000000000..22a822376 --- /dev/null +++ b/quest/m2/ts-model/const-generics.md @@ -0,0 +1,15 @@ +# [M] Const generic types + +## Goal + +[rust2-ts](/ts/README.md) translates structs and enums with const parameters, such as +arrayvec's `ArrayString` and `ArrayVec`, so each instance's body reads its own +`N`, proven by differential tests against native Rust. At the moq pin it refuses once in +the model (`Path::join`'s `ArrayString`) and 8 times in moq-net whole. + +## Plan + +Functions with const parameters already translate per instance; types do not yet. Check +how the choice interacts with a type's class being shared across instances. + +Public API: the translator's output. diff --git a/quest/m2/ts-model/scheduler-hints.md b/quest/m2/ts-model/scheduler-hints.md new file mode 100644 index 000000000..ad0d2ebe9 --- /dev/null +++ b/quest/m2/ts-model/scheduler-hints.md @@ -0,0 +1,14 @@ +# [XS] Scheduler hints + +## Goal + +[rust2-ts](/ts/README.md) translates `thread::yield_now` and `hint::spin_loop` to nothing, +as neither promises anything observable, proven by a differential test against native +Rust. At the moq pin `model/frame.rs`'s `attach` refuses on `yield_now`. + +## Plan + +A spin loop that waits on another thread hangs natively on one thread too, so translating +the hint to nothing matches Rust. + +Public API: the translator's output. diff --git a/quest/m2/ts-model/str-as-ptr.md b/quest/m2/ts-model/str-as-ptr.md new file mode 100644 index 000000000..2c079ee74 --- /dev/null +++ b/quest/m2/ts-model/str-as-ptr.md @@ -0,0 +1,15 @@ +# [S] A string's bytes through its pointer + +## Goal + +[rust2-ts](/ts/README.md) translates `str::as_ptr` as a read-only pointer to the string's +UTF-8, so `ptr::copy_nonoverlapping` and `slice::from_raw_parts` read what Rust reads, +proven by differential tests against native Rust. At the moq pin arrayvec's +`ArrayString` refuses it once in the model and 3 times in moq-net whole. + +## Plan + +A `&str` stays a JS string (decided on #574), so the bytes are an encoding of it; a pointer into +them must not let a write through it go unnoticed, which Rust forbids anyway for a `&str`. + +Public API: the translator's output. diff --git a/quest/m3/ts-uninit-slices.md b/quest/m2/ts-model/uninit-slices.md similarity index 84% rename from quest/m3/ts-uninit-slices.md rename to quest/m2/ts-model/uninit-slices.md index 6e0af7aed..e9950b938 100644 --- a/quest/m3/ts-uninit-slices.md +++ b/quest/m2/ts-model/uninit-slices.md @@ -11,5 +11,5 @@ differential tests against native Rust. A `MaybeUninit` is a `T` in JS, and one of a byte is the byte, so a `[MaybeUninit]` is an `rs.ByteSlice`; `write_copy_of_slice` and a slice's `assume_init_ref` and `assume_init_mut` already map. `write_clone_of_slice` clones in without dropping what was -there, unlike `clone_from_slice`. Found translating `spare_capacity_mut`; no consumer calls -either yet. +there, unlike `clone_from_slice`. Found translating `spare_capacity_mut`. moq-net's `model/frame.rs` calls +`Box::<[u8]>::new_uninit_slice` in `Segment::new` at the moq pin. diff --git a/quest/m2/ts-model/unit-option-fields.md b/quest/m2/ts-model/unit-option-fields.md new file mode 100644 index 000000000..3c411dd22 --- /dev/null +++ b/quest/m2/ts-model/unit-option-fields.md @@ -0,0 +1,18 @@ +# [S] Option fields of a generic type at a unit instance + +## Goal + +[rust2-ts](/ts/README.md) translates a generic type's `Option` or `Poll` field at an +instance whose `T` is itself `undefined` or pending in JS, such as moq-net's `Idle<()>` +(`util/idle.rs`'s `parked`) and tokio's `oneshot::Inner<()>`, proven by differential +tests against native Rust. At the moq pin it refuses 16 times in the model and 24 in +moq-net whole. + +## Plan + +The type's definition types the field `T | undefined`, which loses `Some(())` against +`None` at `T = ()`; the field needs `rs.None` (or `rs.OuterPending`) where an instance +can already be the bare value. Decide it per field from the instances the crate uses, not +per type, and keep the bare form for every other instance. + +Public API: the translator's output. diff --git a/quest/m3/README.md b/quest/m3/README.md index 5c21d0873..d4be3829d 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -22,8 +22,8 @@ generic std gap is planned here even when moq never calls it. - [rs.Slice](/quest/m3/ts-slice-object.md) - references to arrays of other values are a runtime slice too, and pointers compare by where they point - [Writes through iter_mut without a Place per item](/quest/m3/ts-iter-mut-places.md) - a loop over `iter_mut()` of copy values writes the slice's array by index - [rs.String](/quest/m3/ts-string-capacity.md) - `String`, `Box`, and `&str` are a runtime type holding std's capacity -- [Slices not yet written](/quest/m3/ts-uninit-slices.md) - `Box::new_uninit_slice` and `write_clone_of_slice` translate - [Throw only where Rust panics](/quest/m3/ts-runtime-throws.md) - no runtime `rust2-ts:` error where native Rust goes on: an exact slower path, or a refusal at translation - [rust2-ts with no ts.toml](/quest/m3/ts-configless.md) - a crate's whole `pub` API translates with no config and no bound items - [Buf on a deque of bytes](/quest/m3/ts-vecdeque-buf.md) - `bytes`' `Buf` for a deque of bytes translates +- [std's panic messages hold std's capacity](/quest/m3/ts-panic-payload-capacity.md) - a hook reads native's `String` capacity from std's own formatted panics - [A B-tree drops as std's does](/quest/m3/ts-btree-drop-order.md) - keys and values drop node by node, in std's order diff --git a/quest/m3/ts-panic-payload-capacity.md b/quest/m3/ts-panic-payload-capacity.md new file mode 100644 index 000000000..372284152 --- /dev/null +++ b/quest/m3/ts-panic-payload-capacity.md @@ -0,0 +1,20 @@ +# [M] std's panic messages hold std's capacity + +## Goal + +A panic hook in code [rust2-ts](/ts/README.md) generates reads the same `String` capacity +from std's own formatted panic messages (such as `slice index starts at {} but ends at +{}`) as native Rust, proven by the panics fixture's hook against native Rust. + +## Plan + +Found in #574, which gives `String` its capacity: the runtime passes std's formatted messages as one string, so their +capacity differs from std's, which builds them piece by piece (37 against 44 for that +message). About 64 runtime sites pass such a message. Build each as std's `format!` does, +without slowing the paths that never panic. + +Public API: the runtime's panic sites, not their messages. + +## Required + +- [rs.String](/quest/m3/ts-string-capacity.md) - `String` holds std's capacity, which a hook then reads