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 @@ -21,7 +21,6 @@ generic std gap is planned here even when moq never calls it.
- [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
- [A boxed iterator folds as std's box does](/quest/m3/ts-box-folds.md) - a `Box<I>` reads by `next` where std's `Iterator` for `Box<I>` forwards nothing else
- [Placeholders written to a crate's own fmt::Write](/quest/m3/ts-fmt-calls.md) - `write!` with placeholders into a crate's own writer translates, its `write_str` seeing each call std makes
- [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
Expand Down
24 changes: 0 additions & 24 deletions quest/m3/ts-box-folds.md

This file was deleted.

7 changes: 5 additions & 2 deletions ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -506,8 +506,11 @@ behind `&`, `&mut`, `Box`, `Arc`, or `Rc` is an `rt.Iter` of its items, `rt.iter
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, and the last `Arc` the one they
share. `Arc::get_mut` and `Rc::get_mut` of a trait object lend its object while no other
trait object's does. A box of any iterator, a trait object or not, is `rt.iterBox` of it
wherever it is read, behind a `&mut` too: it forwards `next`, `nth`, `last`, and what else
std's `Iterator` for `Box<I>` forwards, and reads the rest by `next`, `advance_by` and the
folds included, so a boxed `skip` of a zip skips through the zip's `nth` as std's does. A
box drops the iterator it owns, and the last `Arc` the one they share. `Arc::get_mut` and `Rc::get_mut` of a trait object lend its object while no other
`Arc` or `Weak` shares it, but a `dyn Any`'s, whose value `Arc::downcast` gives back.

A trait object of std's
Expand Down
21 changes: 21 additions & 0 deletions ts/fixtures/lang/dyns/expected/core/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,27 @@ export function map$0j05j69(self: rt.Arc<rt.u32> | undefined, f: (a0: rt.Arc<rt.
return f(self);
}

export function map$0z7s8q7(self: [Tagged.Tagged, Tagged.Tagged] | undefined, f: (a0: [Tagged.Tagged, Tagged.Tagged]) => [rt.u8, rt.u8]): [rt.u8, rt.u8] | undefined {
if (self === undefined) {
return undefined;
}
return f(self);
}

export function mapOr$1surhce(self: rt.u8 | undefined, default_: rt.u8, f: (a0: rt.u8) => rt.u8): rt.u8 {
if (self === undefined) {
return default_;
}
return f(self);
}

export function mapOr$1ttssgs(self: [rt.u8, rt.ByteSlice] | undefined, default_: [rt.u8, rt.ByteSlice], f: (a0: [rt.u8, rt.ByteSlice]) => [rt.u8, rt.ByteSlice]): [rt.u8, rt.ByteSlice] {
if (self === undefined) {
return default_;
}
return f(self);
}

export function mapOr$06rr3sb(self: rt.u8 | undefined, default_: rt.u8 | undefined, f: (a0: rt.u8) => rt.u8 | undefined): rt.u8 | undefined {
if (self === undefined) {
return default_;
Expand Down
285 changes: 264 additions & 21 deletions ts/fixtures/lang/dyns/expected/dyns.ts

Large diffs are not rendered by default.

22 changes: 15 additions & 7 deletions ts/fixtures/lang/dyns/expected/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import * as rt from "./rt.ts";
import type * as Any from "./core/any.Any.ts";
import { sides$dyns_Shape_u32, intoArea$dyns_Shape_u32, larger$dyns_Shape_u32, tally$dyns_Shape_u32, area$dyns_Shape_u32, grow$dyns_Shape_u32, dyns, shared, asAny$dyns_Erased_u32, asAnyMut$dyns_Erased_u32, key$dyns_Keyed_u32, anys, fns, iters, pointers } from "./dyns.ts";
import { sides$dyns_Shape_u32, intoArea$dyns_Shape_u32, larger$dyns_Shape_u32, tally$dyns_Shape_u32, area$dyns_Shape_u32, grow$dyns_Shape_u32, dyns, shared, asAny$dyns_Erased_u32, asAnyMut$dyns_Erased_u32, key$dyns_Keyed_u32, anys, fns, iters, pointers, boxes } from "./dyns.ts";
import * as Hits from "./dyns.Hits.ts";
import * as Lease from "./dyns.Lease.ts";
import * as Looped from "./dyns.Looped.ts";
import * as Noisy from "./dyns.Noisy.ts";
import * as Square from "./dyns.Square.ts";
import type * as Tagged from "./dyns.Tagged.ts";
import * as Tri from "./dyns.Tri.ts";

export function drop$Result_Rc_dyns_Noisy_Rc_dyn_Any(_1: rt.Result<rt.Arc<Noisy.Noisy>, rt.Arc<Any.Any>>): void {
Expand Down Expand Up @@ -60,6 +61,11 @@ export function drop$Result_u16_boxed_Box_dyn_Any(_1: rt.Result<rt.u16, Any.Any>
}
}

export function drop$tuple2_dyns_Tagged_dyns_Tagged(_1: [Tagged.Tagged, Tagged.Tagged]): void {
_1[0][Symbol.dispose]();
_1[1][Symbol.dispose]();
}

export class of$Option_u8 {
v: rt.u8 | undefined;

Expand Down Expand Up @@ -465,18 +471,20 @@ export class ofPlace$unit {
* their count, so a case added at the end moves no other.
*/
export function cases(): [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined][] {
return [["dyns::dyns", (_22: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): undefined => {
return [["dyns::dyns", (_24: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): undefined => {
dyns(data.data, data.start, data.length, out);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::shared", (_23: rt.u8, data2: rt.ByteSlice, out2: rt.ByteVec): undefined => {
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::shared", (_25: rt.u8, data2: rt.ByteSlice, out2: rt.ByteVec): undefined => {
shared(data2.data, data2.start, data2.length, out2);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::anys", (_24: rt.u8, data3: rt.ByteSlice, out3: rt.ByteVec): undefined => {
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::anys", (_26: rt.u8, data3: rt.ByteSlice, out3: rt.ByteVec): undefined => {
anys(data3.data, data3.start, data3.length, out3);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::fns", (_25: rt.u8, data4: rt.ByteSlice, out4: rt.ByteVec): undefined => {
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::fns", (_27: rt.u8, data4: rt.ByteSlice, out4: rt.ByteVec): undefined => {
fns(data4, out4);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::pointers", (_26: rt.u8, data5: rt.ByteSlice, out5: rt.ByteVec): undefined => {
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::pointers", (_28: rt.u8, data5: rt.ByteSlice, out5: rt.ByteVec): undefined => {
pointers(data5.data, data5.start, data5.length, out5);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::iters", (_27: rt.u8, data6: rt.ByteSlice, out6: rt.ByteVec): undefined => {
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::iters", (_29: rt.u8, data6: rt.ByteSlice, out6: rt.ByteVec): undefined => {
iters(data6, out6);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["dyns::boxes", (_210: rt.u8, data7: rt.ByteSlice, out7: rt.ByteVec): undefined => {
boxes(data7, out7);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]];
}

Expand Down
139 changes: 139 additions & 0 deletions ts/fixtures/lang/dyns/src/dyns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! `dyn Iterator`, `dyn DoubleEndedIterator`, `dyn ExactSizeIterator`, or
//! `dyn FusedIterator` of std's iterators or the crate's own, borrowed, boxed, or shared,
//! reads by its vtable's methods and folds by `next`, dropping what it owns in std's order.
//! A box of an iterator reads by what std's box forwards and folds by `next` too.

use std::any::Any;
use std::cell::RefCell;
Expand Down Expand Up @@ -1062,3 +1063,141 @@ pub fn pointers(data: &[u8], out: &mut Vec<u8>) {
let g: Arc<dyn Fn(u8) -> u8> = Arc::from(boxed);
put(out, &format!("{} {}", f(*b), g(*a)));
}

/// A tag of `t`, below 0x80, which logs it with the high bit set as it is made.
fn made(t: u8) -> Tagged {
DROPS.with_borrow_mut(|d| d.push(t | 0x80));
Tagged(t)
}

/// A skip of a zip std reads by index, of items that log as they are made and dropped, the
/// left side's below 0x40 and the right's above: its `next` skips through the zip's `nth`,
/// which makes and drops each skipped pair a side at a time, where its folds make the pair
/// whole.
fn skipped(data: &[u8]) -> impl DoubleEndedIterator<Item = (Tagged, Tagged)> + ExactSizeIterator + '_ {
let (n, rest) = data.split_first().map_or((0, data), |(n, rest)| (*n, rest));
let (left, right) = rest.split_at(usize::from(n) % (rest.len() + 1));
let left = left.iter().map(|&t| made(t & 0x3f));
left.zip(right.iter().map(|&t| made(t & 0x3f | 0x40)))
.skip(usize::from(n % 3))
}

fn tags(pair: Option<(Tagged, Tagged)>) -> Option<(u8, u8)> {
pair.map(|p| (p.0.0, p.1.0))
}

/// A box of an iterator, owned, behind a `&mut`, of a `&mut`, of a box, and as a trait
/// object: std's `Iterator` for `Box<I>` forwards `next`, `size_hint`, `nth`, `last`, and
/// the double-ended and exact-size methods to `I`, and reads by `next` for the rest, its
/// `advance_by` and folds included.
pub fn boxes(data: &[u8], out: &mut Vec<u8>) {
let it = || Box::new(skipped(data));

// What it forwards.
let mut boxed = it();
let hint = (boxed.size_hint(), boxed.len());
let ends = (tags(boxed.next()), tags(boxed.next_back()));
let nths = (tags(boxed.nth(1)), tags(boxed.nth_back(0)));
dropped(out);
put(out, &format!("{hint:?} {ends:?} {nths:?} "));
drop(boxed);
dropped(out);
put(out, &format!("{:?} ", tags(it().last())));
dropped(out);
put(out, &format!("{:?} ", tags(Box::new(it()).last())));
dropped(out);

// What it reads by `next`.
put(out, &format!("{} ", it().count()));
dropped(out);
let sum = it().fold(0u32, |n, (x, y)| n.wrapping_mul(7).wrapping_add(u32::from(x.0 ^ y.0)));
dropped(out);
put(out, &format!("{sum} "));
it().for_each(|(x, y)| put(out, &format!("{} {} ", x.0, y.0)));
dropped(out);
let found = it().position(|(x, _)| x.0 % 2 == 1);
dropped(out);
put(out, &format!("{found:?} "));
let found = tags(it().find(|(_, y)| y.0 % 3 == 0));
dropped(out);
put(out, &format!("{found:?} {} ", it().any(|(x, _)| x.0 > 8)));
dropped(out);
put(out, &format!("{:?} ", tags(it().max_by_key(|p| p.1.0))));
dropped(out);
let all: Vec<(u8, u8)> = it().collect::<Vec<_>>().into_iter().map(|p| (p.0.0, p.1.0)).collect();
dropped(out);
put(out, &format!("{all:?} "));
let back = it()
.rev()
.fold(0u32, |n, (x, y)| n.wrapping_mul(5).wrapping_add(u32::from(x.0 ^ y.0)));
dropped(out);
put(
out,
&format!(
"{back} {} ",
it().map(|(x, y)| u32::from(x.0) + u32::from(y.0)).sum::<u32>()
),
);
dropped(out);
put(out, &format!("{} {} ", it().skip(1).count(), it().step_by(2).count()));
dropped(out);
// `Chain::nth` advances its first half by `advance_by`, which the box reads by `next`.
put(out, &format!("{:?} ", tags(it().chain(None).nth(1))));
dropped(out);

// Behind a `&mut`, which forwards to the box, and so reads by `next` too, `last` included.
let mut boxed = it();
let last = tags((&mut boxed).last());
dropped(out);
put(out, &format!("{last:?} "));
let mut boxed = it();
let nth = tags((&mut boxed).chain(None).nth(1));
dropped(out);
let n = (&mut boxed).count();
dropped(out);
put(out, &format!("{nth:?} {n} "));
let mut boxed = it();
let first = tags(boxed.next());
let sum = (&mut boxed).fold(0u32, |n, (x, y)| n.wrapping_add(u32::from(x.0 ^ y.0)));
dropped(out);
put(out, &format!("{first:?} {sum} "));
drop(boxed);
dropped(out);

// Of items that never drop: `last` is still what the box holds, whose zip folds no more
// pairs than its size hint, where `next` reads its left side once more.
let n = data.first().map_or(0, |n| n % 4);
let seen = RefCell::new(Vec::new());
let logged = || {
let seen = &seen;
let left = (0..n).chain(n..n + 2).map(move |x| {
seen.borrow_mut().push(x);
x
});
Box::new(left.zip(0..n % 3))
};
let last = logged().last();
let mut boxed = logged();
put(out, &format!("{last:?} {:?} {:?} ", (&mut boxed).last(), seen.borrow()));

// A box of a `&mut`, whose `last` is the borrow's, which folds what it borrows.
let mut held = skipped(data);
put(out, &format!("{:?} ", tags(Box::new(&mut held).last())));
dropped(out);
let mut held = skipped(data);
put(out, &format!("{} ", Box::new(&mut held).count()));
dropped(out);

// A box of a trait object, which reads by `next` where the object reads by its vtable.
let erased = || -> Box<dyn Iterator<Item = (Tagged, Tagged)> + '_> { Box::new(skipped(data)) };
put(out, &format!("{:?} ", tags(erased().chain(None).nth(1))));
dropped(out);
put(out, &format!("{:?} {} ", tags(erased().last()), erased().count()));
dropped(out);
let mut boxed = erased();
let lent: &mut dyn Iterator<Item = (Tagged, Tagged)> = &mut *boxed;
put(out, &format!("{:?} ", tags(lent.chain(None).nth(1))));
dropped(out);
drop(boxed);
dropped(out);
}
1 change: 1 addition & 0 deletions ts/fixtures/lang/dyns/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ fn cases() -> Vec<(&'static str, Case)> {
("dyns::fns", |_, data, out| dyns::fns(data, out)),
("dyns::pointers", |_, data, out| dyns::pointers(data, out)),
("dyns::iters", |_, data, out| dyns::iters(data, out)),
("dyns::boxes", |_, data, out| dyns::boxes(data, out)),
]
}
4 changes: 2 additions & 2 deletions ts/fixtures/lang/iters/expected/iters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9536,8 +9536,8 @@ export function lent(data: rt.ByteSlice, out: rt.ByteVec): void {
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(erased.next()), 238));
rt.iterExtendBytes(out, range, undefined, true);
let boxed: rt.Iter<rt.u8> = rt.iterDyn(rt.iterRev(rt.iterSlice(rt.byteSliceView(data))));
rt.iterExtendBytes(out, rt.iterTake(rt.iterBorrow(boxed), n), "next");
rt.iterExtendBytes(out, rt.iterTake(boxed, 1), "next");
rt.iterExtendBytes(out, rt.iterTake(rt.iterBorrow(rt.iterBox(rt.iterBorrow(boxed))), n), "next");
rt.iterExtendBytes(out, rt.iterTake(rt.iterBox(boxed), 1), "next");
const rest: rt.Iter<rt.u8> = rt.iterSlice(rt.byteSliceView(data));
rt.iterExtendBytes(out, rt.byteVecIntoIter(halves$mut_iter_Copied_slice_Iter_u8(rest, n)), undefined, true);
rt.iterExtendBytes(out, rest, undefined, true);
Expand Down
42 changes: 32 additions & 10 deletions ts/runtime/rt/iter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,15 @@ export function iterDyn<T>(it: Iter<T>): Iter<T> {
return new Dyn(it);
}

/**
* A `Box` of `it`: what std's `Iterator` for `Box<I>` forwards, `last` among them, as `it`
* does it, and the rest by `next`, `advance_by` and the folds included. It drops `it` as it
* drops.
*/
export function iterBox<T>(it: Iter<T>): Iter<T> {
return new Boxed(it);
}

// How std's `Vec` and `VecDeque` reserve for an iterator they collect or extend by, of
// elements `size` bytes each, which panics past what they may hold: a `TrustedLen` one's
// upper bound first, and else, after each item that finds them full, the lower bound and
Expand Down Expand Up @@ -899,6 +908,8 @@ export function iterCount<T>(it: Iter<T>): number {
export function iterLast<T>(it: Iter<T>): T | undefined;
export function iterLast<T>(it: Iter<T>, none: None): T | None;
export function iterLast<T>(it: Iter<T>, none?: None): T | undefined | None {
// std's of a box: what it holds, by its own.
while (it instanceof Boxed) it = it.inner;
const folded = it.folded(true);
let last: T | Done = DONE;
for (let item = folded.next(); item !== DONE; item = folded.next()) last = item;
Expand Down Expand Up @@ -1493,6 +1504,8 @@ function count<T>(it: Iter<T>, drop: Drop<T> | undefined): number {
* does. By `fold`, each item drops as the next replaces it.
*/
function last<T>(it: Iter<T>, drop: Drop<T> | undefined): T | Done {
// std's of a box: what it holds, by its own.
if (it instanceof Boxed) return last(it.inner, drop);
if ((it instanceof SliceIter && drop !== undefined) || (it instanceof BTreeIter && it.back)) {
// std's, of a `Vec`'s or an array's, and of a B-tree's `into_keys` and
// `into_values`: the last item, and then the rest drop with it.
Expand Down Expand Up @@ -2059,8 +2072,11 @@ class SuccessorsIter<T> extends Iter<T> implements Disposable {
}
}

/** What std's vtable of an iterator holds, as `inner` does it, which it drops with itself. */
class Dyn<T> extends Iter<T> implements Disposable {
/**
* An iterator of `inner` that forwards what std's `Iterator` for `Box<I>` and a trait
* object's vtable both have, and drops it as it drops.
*/
abstract class Forward<T> extends Iter<T> implements Disposable {
readonly inner: Iter<T>;

constructor(inner: Iter<T>) {
Expand All @@ -2084,14 +2100,6 @@ class Dyn<T> extends Iter<T> implements Disposable {
return this.inner.len();
}

override advanceBy(n: number, drop?: Drop<T>): number {
return this.inner.advanceBy(n, drop);
}

override advanceBackBy(n: number, drop?: Drop<T>): number {
return this.inner.advanceBackBy(n, drop);
}

override nth(n: number, drop?: Drop<T>): T | Done {
return this.inner.nth(n, drop);
}
Expand All @@ -2105,6 +2113,20 @@ class Dyn<T> extends Iter<T> implements Disposable {
}
}

/** A box, whose `last` is `inner`'s too, which `last` dispatches on. */
class Boxed<T> extends Forward<T> {}

/** What std's vtable of an iterator holds, as `inner` does it: a box's, and `advance_by` too. */
class Dyn<T> extends Forward<T> {
override advanceBy(n: number, drop?: Drop<T>): number {
return this.inner.advanceBy(n, drop);
}

override advanceBackBy(n: number, drop?: Drop<T>): number {
return this.inner.advanceBackBy(n, drop);
}
}

/**
* An iterator borrowed by `&mut`, which forwards only what std's `impl Iterator for &mut
* I` does, its folds included, as std's specializes them for a sized `I`, and which
Expand Down
Loading