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
5 changes: 2 additions & 3 deletions quest/m2/ts-model/rangemap.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ proven by differential tests against native Rust. At the pin it refuses 11 times

## Plan

[B-tree searches calling `Ord` as std's do](/quest/m3/ts-btree-search-order.md) is
related: a search by a borrowed form calls that form's `Ord`, so the comparisons it makes
should match std's. A field of std's iterator type is the runtime's `rs.Iter`, as a local
The runtime's B-tree calls `Ord::cmp` as std's does, `key.cmp(k)` node by node, so a
search by a borrowed form calls that form's `Ord` where std's would. A field of std's iterator type is the runtime's `rs.Iter`, as a local
of that type already is.
1 change: 0 additions & 1 deletion quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,4 @@ 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<str>`, and `&str` are a runtime type holding std's capacity
- [A B-tree's searches call Ord as std's do](/quest/m3/ts-btree-search-order.md) - a B-tree's lookups and inserts call a key's own `Ord` in std's order and number
- [Slices not yet written](/quest/m3/ts-uninit-slices.md) - `Box::new_uninit_slice` and `write_clone_of_slice` translate
18 changes: 0 additions & 18 deletions quest/m3/ts-btree-search-order.md

This file was deleted.

24 changes: 14 additions & 10 deletions ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,9 @@ A write of a value of no bytes, through a `&mut` or a pointer, reads and writes
A collection keeps Rust's key semantics. A hash map or set keeps a key that is a JS
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
`Eq`; a B-tree orders every key by its translated `Ord`, calling `cmp` on the keys std's
does, in the same order, so a tree a `collect` sorted by a `lt` that disagrees answers as
std's does. std's impls are the runtime's: an
`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
Expand Down Expand Up @@ -975,12 +977,15 @@ they need.
the long-lived slot, which made Chrome's 8-byte leading-ones varints 1.06-1.09x `main`'s
time. A slice's bytes stay in the slot, since returning them gave back frame decode. The
function as a value is an arrow that rebuilds the `Result`.
- A `BTreeMap` is a B+ tree of up to 64 keys a node, O(log n) as std's B-tree is: its
leaves hold the keys and values and link to their neighbors, which iterators walk from
either end, and its branches hold each child's lower bound. A node's slots shift in a
loop, which beat `splice` 2-3x at these sizes. On `just ts bench`'s `btree/` workloads
it takes 0.5-0.8x the time two sorted arrays did, from 16 keys to 4096, in Node, Bun,
and Chrome; 64 keys a node measured best of 16 to 128. A hash map's JS primitive keys
- A `BTreeMap` is std's B-tree, ported: nodes of up to 11 keys with their values,
children below internal ones, each searched from its first key by `key.cmp(k)`, split,
merged, and evened out with a sibling where std's are, built by `collect` and
`split_off` as std's builds them, and cloned node for node, so a key's own `cmp` runs
on the same keys in the same order as std's. Iterators climb and descend leaf edges as
std's do. On `just ts bench`'s `btree/` workloads it takes 0.8-1.0x the time the B+
tree of 64-key nodes it replaced did in Chrome, 1.0-1.3x in Node and Firefox, within
their noise, and 1.3-1.6x in Bun, from 16 keys to 4096; bisecting a node's keys measured
no faster. A hash map's JS primitive keys
are a JS `Map`'s, the engine's own hash table; its other keys go into a second `Map`
by their translated hash, chained by `Eq`. A hash map, set, or table holds only what std
guarantees of its capacity, at least its length and what `with_capacity` and `reserve`
Expand Down Expand Up @@ -1010,9 +1015,8 @@ they need.
so `append` is O(1) and `split_off` walks from the nearer end; each node is the place
`iter_mut` and `front_mut` lend of an item JS copies. Dropping a whole map or set drops its entries in the
runtime's order, keys' for a B-tree, not std's node by node: std leaves that order
undocumented, and matching it would mean porting std's 11-key node layout, measured 1.5x
slower ([#272](https://github.com/moq-dev/rust2/pull/272)). Maintainer's decision on
2026-10-30; a map's `IntoIter` still drops in std's order.
undocumented ([#272](https://github.com/moq-dev/rust2/pull/272)). Maintainer's decision
on 2026-10-30; a map's `IntoIter` still drops in std's order.
- A slice's `sort` and `sort_unstable` are std's driftsort and ipnsort, ported to the
runtime with the choices std makes by the element's size on wasm32 and whether it is
`Freeze` and `Copy`, so each calls the comparator in std's order and leaves equal
Expand Down
56 changes: 56 additions & 0 deletions ts/fixtures/lang/collections/expected/collections.Probe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Generated by rust2-ts. Do not edit.

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

/**
* A B-tree key that logs each comparison std makes of it, in order: `cmp` and `eq` by its
* low 10 bits, `le` and `gt` alike, but `lt`, which a set's `collect` sorts by, by those
* bits with the low 2 flipped, and `ne`, which `collect` drops all but the last of a run of
* equal keys by, by all 16. A collected tree is then out of `cmp`'s order, or holds keys
* `cmp` finds equal.
*/
export interface Probe {
_0: rs.u16;
_1: rs.Cell<rs.u32>;
}

export function log(self: Probe, other: Probe, by: rs.u32): void {
const call: rs.u32 = ((((((self._0 as rs.u32) << 16) >>> 0) ^ other._0 as rs.u32) >>> 0) ^ by) >>> 0;
rs.cellSet(self._1, rs.u32WrappingAdd(rs.u32WrappingMul(self._1.v, 16777619), call));
}

export function low(self: Probe): rs.u16 {
return self._0 & 1023;
}

export function eq$cmp_PartialEq(self: Probe, other: Probe): boolean {
log(self, other, 256);
return low(self) === low(other);
}

export function ne$cmp_PartialEq(self: Probe, other: Probe): boolean {
log(self, other, 512);
return self._0 !== other._0;
}

export function lt$cmp_PartialOrd(self: Probe, other: Probe): boolean {
log(self, other, 1024);
return (low(self) ^ 3) < (low(other) ^ 3);
}

export function le$cmp_PartialOrd(self: Probe, other: Probe): boolean {
log(self, other, 1280);
return low(self) <= low(other);
}

export function gt$cmp_PartialOrd(self: Probe, other: Probe): boolean {
log(self, other, 1536);
return low(self) > low(other);
}

export function cmp$cmp_Ord(self: Probe, other: Probe): rs.Ordering {
log(self, other, 2048);
return rs.cmp(low(self), low(other));
}

//# sourceMappingURL=collections.Probe.ts.map
Loading