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
4 changes: 2 additions & 2 deletions quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ 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 Error`'s downcasts, `dyn FusedIterator`, and `Arc<dyn Iterator>` translate, so a consumer neither rewrites nor binds them
- [Trait objects](/quest/m3/ts-dyn.md) - `dyn Error`'s downcasts 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
- [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
- [by_ref of a mutable reference to an iterator](/quest/m3/ts-by-ref-place.md) - `Iterator::by_ref` of a `&mut I` in a local translates
- [mem::take as a function value](/quest/m3/ts-take-value.md) - `mem::take`, `replace`, and `swap` passed as a function value translate
- [Debug of a RefCell](/quest/m3/ts-refcell-debug.md) - `{:?}` of a `RefCell`, `Ref`, and `RefMut` translates as std's writes them
- [Debug of a RefCell or a Cell](/quest/m3/ts-refcell-debug.md) - `{:?}` of a `RefCell`, `Ref`, `RefMut`, and `Cell` translates as std's writes them
- [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
13 changes: 6 additions & 7 deletions quest/m3/ts-dyn.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# [L] Trait objects
# [M] Trait objects

## Goal

[rust2-ts](/ts/README.md) translates the trait objects of std's and mapped crates' traits
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.
[rust2-ts](/ts/README.md) translates `dyn Error`'s downcasts, with Rust's answers for a
value upcast from the crate's own trait, proven by differential tests against native Rust,
so a consumer neither rewrites nor binds them.

## Plan

Expand All @@ -16,7 +14,8 @@ 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, `dyn Iterator` and its subtraits as an `rt.Iter`, and the translated
closure itself, `dyn Iterator` and its subtraits as an `rt.Iter`, behind `&`, `&mut`,
`Box`, `Arc`, and `Rc`, 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
Expand Down
11 changes: 7 additions & 4 deletions quest/m3/ts-refcell-debug.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
# [XS] Debug of a RefCell
# [XS] Debug of a RefCell or a Cell

## Goal

[rust2-ts](/ts/README.md) translates `{:?}` of a `RefCell` and its `Ref` and `RefMut`,
writing `RefCell { value: .. }` and `<borrowed>` while mutably borrowed as std's does,
proven by a differential test against native Rust.
writing `RefCell { value: .. }` and `<borrowed>` while mutably borrowed as std's does, and
of a `Cell` of a `Copy` value, writing `Cell { value: .. }`, proven by a differential test
against native Rust.

## Plan

Found writing [`Box<dyn Debug>`](https://github.com/moq-dev/rust2/pull/445): it is an
"unsupported call to `<RefCell<Vec<u8>> as Debug>::fmt`".
"unsupported call to `<RefCell<Vec<u8>> as Debug>::fmt`". `Cell`'s, found writing
[`&mut dyn Debug`](https://github.com/moq-dev/rust2/pull/453), is the same; the
maintainer chose on 2026-11-02 to cover both here.

Public API: the translator's output.
10 changes: 6 additions & 4 deletions ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +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 |
| `dyn Iterator`, `dyn DoubleEndedIterator`, `dyn ExactSizeIterator`, `dyn FusedIterator` | `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 @@ -493,12 +493,14 @@ 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
A `dyn Iterator`, `dyn DoubleEndedIterator`, `dyn ExactSizeIterator`, or `dyn FusedIterator`
behind `&`, `&mut`, `Box`, `Arc`, or `Rc` 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.
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
`Arc` or `Weak` shares it, but a `dyn Any`'s, whose value `Arc::downcast` gives back.

A trait object of std's
or a mapped crate's trait other than `dyn Debug` and `dyn Display` behind `&`, `&mut`,
Expand Down
28 changes: 28 additions & 0 deletions ts/fixtures/lang/expected/core/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,13 @@ export function map$1i542n2(self: rt.Arc<dyns_Shape.Shape> | undefined, f: (a0:
return f(self);
}

export function map$0oedb57(self: rt.Arc<rt.Iter<rt.u8>> | undefined, f: (a0: rt.Arc<rt.Iter<rt.u8>>) => [rt.usize, rt.usize | undefined]): [rt.usize, rt.usize | undefined] | undefined {
if (self === undefined) {
return undefined;
}
return f(self);
}

export function map$1mp7tga(self: rt.i64[] | undefined, f: (a0: rt.i64[]) => rt.usize): rt.usize | undefined {
if (self === undefined) {
return undefined;
Expand Down Expand Up @@ -393,6 +400,13 @@ export function map$1jcn6wm(self: rt.ByteSlice | undefined, f: (a0: rt.ByteSlice
return f(self);
}

export function map$1qfllpb(self: rt.Iter<rt.u8> | undefined, f: (a0: rt.Iter<rt.u8>) => rt.u8 | undefined): rt.u8 | undefined | rt.None {
if (self === undefined) {
return rt.None;
}
return f(self);
}

export function map$1k7m6zz(self: [rt.u8, rt.u8] | undefined, f: (a0: [rt.u8, rt.u8]) => [rt.u8, rt.u8]): [rt.u8, rt.u8] | undefined {
if (self === undefined) {
return undefined;
Expand Down Expand Up @@ -1740,6 +1754,20 @@ export function andThen$0qni7te(self: rt.u8 | undefined | rt.None, f: (a0: rt.u8
return f(self);
}

export function andThen$0v0bj8w(self: rt.Iter<dyns_Tagged.Tagged> | undefined, f: (a0: rt.Iter<dyns_Tagged.Tagged>) => dyns_Tagged.Tagged | undefined): dyns_Tagged.Tagged | undefined {
if (self === undefined) {
return undefined;
}
return f(self);
}

export function andThen$0ntiuws(self: rt.Iter<rt.u8> | undefined, f: (a0: rt.Iter<rt.u8>) => rt.u8 | undefined): rt.u8 | undefined {
if (self === undefined) {
return undefined;
}
return f(self);
}

export function andThen$101gy6h(self: rt.Place<rt.u32> | undefined, f: (a0: rt.Place<rt.u32>) => rt.Place<rt.u32> | undefined): rt.Place<rt.u32> | undefined {
if (self === undefined) {
return undefined;
Expand Down
21 changes: 21 additions & 0 deletions ts/fixtures/lang/expected/dyns.Resuming.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";

/** Counts down to its end, then starts over, as a fused iterator never does. */
export interface Resuming {
_0: rt.u8;
}

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

//# sourceMappingURL=dyns.Resuming.ts.map
101 changes: 99 additions & 2 deletions ts/fixtures/lang/expected/dyns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as rt from "./rt.ts";
import { drop$Result_Rc_dyns_Noisy_Rc_dyn_Any, drop$Result_Rc_dyns_Square_Rc_dyn_Any, drop$Result_Rc_dyns_Tri_Rc_dyn_Any } from "./lib.ts";
import * as Any from "./core/any.Any.ts";
import { thenSome$0d5am30 } from "./core/bool.ts";
import { unwrapOr$1iemzn8 as option_unwrapOr$1iemzn8, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$1i542n2 as option_map$1i542n2, map$08a6hpg as option_map$08a6hpg, map$0j05j69 as option_map$0j05j69, mapOr$06rr3sb as option_mapOr$06rr3sb } from "./core/option.ts";
import { unwrapOr$1iemzn8 as option_unwrapOr$1iemzn8, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$1i542n2 as option_map$1i542n2, map$0oedb57 as option_map$0oedb57, map$08a6hpg as option_map$08a6hpg, map$1qfllpb as option_map$1qfllpb, map$0j05j69 as option_map$0j05j69, mapOr$06rr3sb as option_mapOr$06rr3sb, andThen$0v0bj8w as option_andThen$0v0bj8w, andThen$0ntiuws as option_andThen$0ntiuws } from "./core/option.ts";
import { ok$00p9ap8, ok$0lceojf, map$0zzqmaz as result_map$0zzqmaz } from "./core/result.ts";
import * as Chunks from "./dyns.Chunks.ts";
import * as dyns_Countdown from "./dyns.Countdown.ts";
Expand All @@ -14,6 +14,7 @@ import * as Hook from "./dyns.Hook.ts";
import * as Looped from "./dyns.Looped.ts";
import * as dyns_Named from "./dyns.Named.ts";
import * as dyns_Noisy from "./dyns.Noisy.ts";
import * as Resuming from "./dyns.Resuming.ts";
import * as dyns_Shape from "./dyns.Shape.ts";
import * as Shown from "./dyns.Shown.ts";
import * as Square from "./dyns.Square.ts";
Expand Down Expand Up @@ -874,10 +875,106 @@ export function iters(data: rt.ByteSlice, out: rt.ByteVec): void {
}), "next", 4);
const _369: rt.usize = rt.ownedCount(split.chunks$Chunks());
const args20: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtList(lens_, f, rt.usizeDebug), (f: rt.Formatter) => rt.usizeDisplay(_369, f)];
fmt_put(out, rt.fmtFormat([args20[0], " ", args20[1]]));
fmt_put(out, rt.fmtFormat([args20[0], " ", args20[1], " "]));
const part3 = drain(rt.iterDyn(rt.iterBorrow(rt.iterFuse(rt.iterFrom({ _0: rt.u8Rem(a, 4) }, (it: Resuming.Resuming) => Resuming.next$iter_Iterator(it))))));
const args22: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtPad(f, part3)];
fmt_put(out, rt.fmtFormat([args22[0], " "]));
const resuming: Resuming.Resuming = { _0: rt.u8Rem(b, 4) };
const up: rt.Iter<rt.u8> = rt.iterDyn(rt.iterFrom(resuming, (it: Resuming.Resuming) => Resuming.next$iter_Iterator(it)));
const part4 = [rt.iterToOption(up.next()), rt.iterToOption(up.next()), rt.iterToOption(up.next()), rt.iterToOption(up.next()), rt.iterToOption(up.next())] as [rt.u8 | undefined, rt.u8 | undefined, rt.u8 | undefined, rt.u8 | undefined, rt.u8 | undefined];
const args24: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.fmtOption(part4[0], f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(part4[1], f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(part4[2], f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(part4[3], f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(part4[4], f, rt.u8Debug)], f)];
fmt_put(out, rt.fmtFormat([args24[0], " "]));
const boxed3: rt.Iter<rt.u8> = rt.iterDyn(rt.iterFrom(new dyns_Countdown.Countdown(rt.u8Rem(a, 8)), (it: dyns_Countdown.Countdown) => dyns_Countdown.next$iter_Iterator(it), rt.drop));
const part5 = drain(boxed3);
const args26: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtPad(f, part5)];
fmt_put(out, rt.fmtFormat([args26[0], " "]));
rt.drop(boxed3);
dropped(out);
const concrete: rt.Arc<rt.Iter<dyns_Tagged.Tagged>> = new rt.Arc(rt.iterSlice(tagged(front), rt.drop));
const shared: rt.Arc<rt.Iter<dyns_Tagged.Tagged>> = new rt.ArcDyn(concrete, rt.iterDyn(concrete.value));
const other: rt.Arc<rt.Iter<dyns_Tagged.Tagged>> = rt.arcClone(shared);
const weak: rt.Weak<rt.Iter<dyns_Tagged.Tagged>> = new rt.Weak(other);
const _456: [rt.usize, rt.usize | undefined] = other.value.sizeHint();
const _460: boolean = rt.arcGetMut(shared) === undefined;
const args28: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.usizeDebug(_456[0], f), (f: rt.Formatter) => rt.fmtOption(_456[1], f, rt.usizeDebug)], f), (f: rt.Formatter) => rt.fmtBool(_460, f)];
fmt_put(out, rt.fmtFormat([args28[0], " ", args28[1], " "]));
other[Symbol.dispose]();
weak[Symbol.dispose]();
const taken: rt.u8 | undefined = option_map$08a6hpg(option_andThen$0v0bj8w(rt.arcGetMut(shared), (it2: rt.Iter<dyns_Tagged.Tagged>): dyns_Tagged.Tagged | undefined => {
return rt.iterToOption(it2.next());
}), (t5: dyns_Tagged.Tagged): rt.u8 => {
const _013: rt.u8 = t5._0;
t5[Symbol.dispose]();
return _013;
});
dropped(out);
const args30: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(taken, f, rt.u8Debug)];
fmt_put(out, rt.fmtFormat([args30[0], " "]));
shared[Symbol.dispose]();
dropped(out);
const _492: rt.Arc<rt.Iter<rt.u8>> = new rt.Arc(rt.byteVecIntoIter(rt.byteSliceToByteVec(back)));
const exact: rt.Arc<rt.Iter<rt.u8>> = new rt.ArcDyn(_492, rt.iterDyn(_492.value));
const up2: rt.Arc<rt.Iter<rt.u8>> = rt.arcClone(exact);
const _506: rt.usize = exact.value.len();
const _510: rt.u8 | undefined | rt.None = option_map$1qfllpb(rt.arcGetMut(up2), (it3: rt.Iter<rt.u8>): rt.u8 | undefined => {
return rt.iterToOption(it3.next());
});
const args32: rt.Fmt[] = [(f: rt.Formatter) => rt.usizeDisplay(_506, f), (f: rt.Formatter) => rt.fmtOption(_510, f, (value: rt.u8 | undefined, f: rt.Formatter) => rt.fmtOption(value, f, rt.u8Debug), rt.None)];
fmt_put(out, rt.fmtFormat([args32[0], " ", args32[1], " "]));
exact[Symbol.dispose]();
const next: rt.u8 | undefined = option_andThen$0ntiuws(rt.arcGetMut(up2), (it4: rt.Iter<rt.u8>): rt.u8 | undefined => {
return rt.iterToOption(it4.next());
});
const _530: [rt.usize, rt.usize | undefined] = up2.value.sizeHint();
const args34: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(next, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.usizeDebug(_530[0], f), (f: rt.Formatter) => rt.fmtOption(_530[1], f, rt.usizeDebug)], f)];
fmt_put(out, rt.fmtFormat([args34[0], " ", args34[1], " "]));
const fromBox: rt.Arc<rt.Iter<rt.u8>> = new rt.Arc(rt.iterDyn(rt.iterFrom(new dyns_Countdown.Countdown(rt.u8Rem(b, 8)), (it: dyns_Countdown.Countdown) => dyns_Countdown.next$iter_Iterator(it), rt.drop)));
const part6 = option_andThen$0ntiuws(rt.arcGetMut(fromBox), (it5: rt.Iter<rt.u8>): rt.u8 | undefined => {
return rt.iterToOption(it5.next());
});
const args36: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part6, f, rt.u8Debug)];
fmt_put(out, rt.fmtFormat([args36[0], " "]));
fromBox[Symbol.dispose]();
dropped(out);
const counted2: rt.Arc<dyns_Countdown.Countdown> = new rt.Arc(new dyns_Countdown.Countdown(rt.u8Rem(a, 8)));
const weak3: rt.Weak<rt.Iter<rt.u8>> = rt.weakDyn(new rt.Weak(counted2), (arc: rt.Arc<dyns_Countdown.Countdown>): rt.Arc<rt.Iter<rt.u8>> => {
return new rt.ArcDyn(arc, rt.iterDyn(rt.iterFrom(arc.value, (it: dyns_Countdown.Countdown) => dyns_Countdown.next$iter_Iterator(it), rt.drop)));
});
const part7 = option_map$0oedb57(rt.weakUpgrade(weak3), (it6: rt.Arc<rt.Iter<rt.u8>>): [rt.usize, rt.usize | undefined] => {
const _017: [rt.usize, rt.usize | undefined] = it6.value.sizeHint();
it6[Symbol.dispose]();
return _017;
});
const args38: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part7, f, (value: [rt.usize, rt.usize | undefined], f: rt.Formatter) => rt.fmtTuple([(f: rt.Formatter) => rt.usizeDebug(value[0], f), (f: rt.Formatter) => rt.fmtOption(value[1], f, rt.usizeDebug)], f))];
fmt_put(out, rt.fmtFormat([args38[0], " "]));
counted2[Symbol.dispose]();
const _596: rt.Arc<rt.Iter<rt.u8>> | undefined = rt.weakUpgrade(weak3);
const part8 = _596 === undefined;
const args40: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtBool(part8, f)];
const _590: string = rt.fmtFormat([args40[0], " "]);
rt.drop(_596);
fmt_put(out, _590);
dropped(out);
const pinned: rt.Iter<rt.u8> = rt.iterDyn(rt.iterFrom(new dyns_Countdown.Countdown(rt.u8Rem(b, 8)), (it: dyns_Countdown.Countdown) => dyns_Countdown.next$iter_Iterator(it), rt.drop));
const part9 = rt.iterToOption(pinned.next());
const args42: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtOption(part9, f, rt.u8Debug)];
fmt_put(out, rt.fmtFormat([args42[0]]));
rt.drop(pinned);
dropped(out);
weak3[Symbol.dispose]();
up2[Symbol.dispose]();
}
}

/** What `it` yields up to its end and twice past it. */
export function drain(it: rt.Iter<rt.u8>): string {
const items: rt.ByteVec = rt.iterToByteVec(rt.iterBorrow(it), "next");
const _7: rt.u8 | undefined = rt.iterToOption(it.next());
const _9: rt.u8 | undefined = rt.iterToOption(it.next());
const args2: rt.Fmt[] = [(f: rt.Formatter) => rt.fmtList(rt.byteVecView(items), f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(_7, f, rt.u8Debug), (f: rt.Formatter) => rt.fmtOption(_9, f, rt.u8Debug)];
return rt.fmtFormat([args2[0], " ", args2[1], " ", args2[2]]);
}

/**
* Trait objects behind the rest of the pointers std coerces to one: an `Rc`, a `Weak` of
* an `Rc` or an `Arc`, a `Pin`, and an `Rc` or an `Arc` made from a box of one. Counts,
Expand Down
Loading