Skip to content
1 change: 0 additions & 1 deletion quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ generic std gap is planned here even when moq never calls it.
- [A vector's exact capacity as it shrinks](/quest/m3/ts-vec-exact-capacity.md) - a deque made from a `Vec` splits its slices where std's does
- [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
- [Rc and Arc of a slice](/quest/m3/ts-shared-slices.md) - `Rc<[T]>` and `Arc<[T]>` from a `Vec`, a slice, or an iterator translate
- [Whether a type needs drop](/quest/m3/ts-needs-drop.md) - `mem::needs_drop::<T>()` translates as rustc's constant for each instance
- [Operator trait methods called by path](/quest/m3/ts-operator-paths.md) - `<u8 as AddAssign>::add_assign` and every other `std::ops` operator method translate called by path or as a value
- [The rest of a vector's methods](/quest/m3/ts-vec-rest.md) - `append`, `resize`, `split_off`, `try_reserve`, and `Vec::from(VecDeque)` translate
- [A reversed zip's per-pair cost](/quest/m3/ts-zip-rev-overhead.md) - a reversed by-index zip costs per pair what a forward one does, or the gap is explained
Expand Down
18 changes: 0 additions & 18 deletions quest/m3/ts-needs-drop.md

This file was deleted.

6 changes: 6 additions & 0 deletions ts/fixtures/lang/manual/expected/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,10 @@ export function op(name: string): rt.u16 {
}
}

/** Write `s` and the byte no UTF-8 holds, which ends it. */
export function put(out: rt.ByteVec, s: string): void {
rt.byteVecExtendFromSlice(out, rt.stringAsBytes(s));
rt.byteVecPush(out, 255);
}

//# sourceMappingURL=harness.ts.map
4 changes: 3 additions & 1 deletion ts/fixtures/lang/manual/expected/lib.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Generated by rust2-ts. Do not edit.

import * as rt from "./rt.ts";
import { arcs } from "./manual.ts";
import { arcs, needsDrops } from "./manual.ts";

export function copy$array_u8(v: Uint8Array): Uint8Array {
return v.slice();
Expand All @@ -25,6 +25,8 @@ export function copy$tuple2_u8_u16(v: [rt.u8, rt.u16]): [rt.u8, rt.u16] {
export function cases(): [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined][] {
return [["manual::arcs", (_22: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): undefined => {
arcs(data, out);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["manual::needs_drops", (_23: rt.u8, data2: rt.ByteSlice, out2: rt.ByteVec): undefined => {
needsDrops(data2, out2);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]];
}

Expand Down
104 changes: 104 additions & 0 deletions ts/fixtures/lang/manual/expected/manual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import * as rt from "./rt.ts";
import { copy$array_u8, copy$mem_MaybeUninit_mem_ManuallyDrop_tuple2_u8_u16, copy$tuple2_u8_u16 } from "./lib.ts";
import { put } from "./harness.ts";
import * as ByHand from "./manual.ByHand.ts";

/** A value's `ManuallyDrop`, as a generic one makes it, which only an instance lays out. */
Expand Down Expand Up @@ -77,4 +78,107 @@ export function arcs(data: rt.ByteSlice, out: rt.ByteVec): void {
shared[Symbol.dispose]();
}

/** Whether `T` needs dropping, as rustc says of each instance. */
export function needs$String(): boolean {
return true;
}

/** Whether `T` needs dropping, as rustc says of each instance. */
export function needs$manual_ByHand(): boolean {
return true;
}

/** Whether `T` needs dropping, as rustc says of each instance. */
export function needs$u8(): boolean {
return false;
}

/** Whether `T` needs dropping, as rustc says of each instance. */
export function needs$unit(): boolean {
return false;
}

/**
* Whether each type needs dropping, of values JS copies or drops nothing of, such as a
* `String`, held by hand, in an empty array, and of a closure by what it captures; what a
* generic body that branches on it does, as std's collections do; and types' names.
*/
export function needsDrops(data: rt.ByteSlice, out: rt.ByteVec): void {
const captured = rt.stringExtendChars("", rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_2: rt.u8): rt.char => {
return _2 as rt.char;
}));
const named: () => rt.usize = (): rt.usize => {
return rt.stringLen(captured);
};
const copied: () => rt.usize = (): rt.usize => {
return data.length;
};
rt.iterExtendBytes(out, rt.iterSlice(rt.bytesMap([false, false, true, false, false, false, true, true, true, true, true, true, false, true, true, false, true, false, false, true, false, false, false, true, true, false, needs$String(), needs$u8(), needs$manual_ByHand(), needs$unit(), needsDropOf$manual_needs_drops_closure1(named), needsDropOf$manual_needs_drops_closure2(copied)], (a0: boolean): rt.u8 => {
return a0 ? 1 : 0;
})), undefined, true);
rt.byteVecPush(out, (named() & 0xff) ^ (copied() & 0xff));
rt.iterExtendBytes(out, rt.iterSlice(rt.u32ToBeBytes(droppedByHand$String(rt.iterToArray(rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (b2: rt.u8): string => {
return rt.fmtToString((f: rt.Formatter) => rt.u8Display(b2, f));
}), undefined, 12, true))).reverse()), undefined, true);
rt.iterExtendBytes(out, rt.iterSlice(rt.u32ToBeBytes(droppedByHand$u8(rt.byteSliceToByteVec(data))).reverse()), undefined, true);
const iter: rt.Iter<string> = rt.iterSlice(["lang_manual_fixture::manual::ByHand", "core::option::Option<&[alloc::string::String]>", "lang_manual_fixture::manual::needs_drops::{{closure}}", "[u8]", nameOf$u8(), nameOf$String()]);
while (true) {
const _73: string | rt.Done = iter.next();
if (_73 === rt.DONE) {
break;
}
put(out, _73);
}
}

/** Whether the value's type needs dropping. */
export function needsDropOf$manual_needs_drops_closure1(_1: () => rt.usize): boolean {
return true;
}

/** Whether the value's type needs dropping. */
export function needsDropOf$manual_needs_drops_closure2(_1: () => rt.usize): boolean {
return false;
}

/** `T`'s name, as a generic body names it. */
export function nameOf$String(): string {
return "alloc::string::String";
}

/** `T`'s name, as a generic body names it. */
export function nameOf$u8(): string {
return "u8";
}

/**
* How many items a generic body drops one by one, as std's collections do only of a type
* that needs dropping, and forgets the rest.
*/
export function droppedByHand$String(items: string[]): rt.u32 {
if (false) {
return 0;
}
let n: rt.u32 = 0;
for (const _7 of items) {
n = rt.u32Add(n, 1);
}
return n;
}

/**
* How many items a generic body drops one by one, as std's collections do only of a type
* that needs dropping, and forgets the rest.
*/
export function droppedByHand$u8(items: rt.ByteVec): rt.u32 {
if (true) {
return 0;
}
let n: rt.u32 = 0;
for (const _7 of rt.byteVecView(items)) {
n = rt.u32Add(n, 1);
}
return n;
}

//# sourceMappingURL=manual.ts.map
5 changes: 4 additions & 1 deletion ts/fixtures/lang/manual/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@ use harness::Case;
/// Each case's name and what it runs. The first two bytes, big-endian, pick one modulo
/// their count, so a case added at the end moves no other.
fn cases() -> Vec<(&'static str, Case)> {
vec![("manual::arcs", |_, data, out| manual::arcs(data, out))]
vec![
("manual::arcs", |_, data, out| manual::arcs(data, out)),
("manual::needs_drops", |_, data, out| manual::needs_drops(data, out)),
]
}
98 changes: 96 additions & 2 deletions ts/fixtures/lang/manual/src/manual.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
//! `ManuallyDrop`: a value nothing drops but its own `drop`, given back by `into_inner`
//! and `take`, cloned, and read and written through it as `Deref` and `DerefMut` lend it,
//! as crossbeam-epoch's `Local` holds its collector and futures-util a waker.
//! as crossbeam-epoch's `Local` holds its collector and futures-util a waker; and
//! `needs_drop` and `type_name`, which rustc answers for each instance.

use std::mem::{ManuallyDrop, MaybeUninit};
use std::any::{type_name, type_name_of_val};
use std::cell::Cell;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem::{ManuallyDrop, MaybeUninit, needs_drop};
use std::rc::Rc;
use std::sync::Arc;

/// The crate's struct holding values by hand, which its `Drop` drops one of.
Expand Down Expand Up @@ -85,3 +91,91 @@ pub fn arcs(data: &[u8], out: &mut Vec<u8>) {
drop(kept);
out.push(Arc::strong_count(&shared) as u8);
}

/// Whether `T` needs dropping, as rustc says of each instance.
fn needs<T: ?Sized>() -> bool {
needs_drop::<T>()
}

/// Whether each type needs dropping, of values JS copies or drops nothing of, such as a
/// `String`, held by hand, in an empty array, and of a closure by what it captures; what a
/// generic body that branches on it does, as std's collections do; and types' names.
pub fn needs_drops(data: &[u8], out: &mut Vec<u8>) {
let text: String = data.iter().map(|&b| char::from(b)).collect();
let named = move || text.len();
let copied = move || data.len();
let flags = [
needs_drop::<u8>(),
needs_drop::<u128>(),
needs_drop::<String>(),
needs_drop::<&String>(),
needs_drop::<&mut Vec<u8>>(),
needs_drop::<str>(),
needs_drop::<[String]>(),
needs_drop::<dyn Debug>(),
needs_drop::<Vec<u8>>(),
needs_drop::<Box<u8>>(),
needs_drop::<Rc<u8>>(),
needs_drop::<Arc<u8>>(),
needs_drop::<Option<u8>>(),
needs_drop::<Option<String>>(),
needs_drop::<Result<u8, String>>(),
needs_drop::<(u8, u16)>(),
needs_drop::<(u8, String)>(),
needs_drop::<[u8; 4]>(),
needs_drop::<[String; 0]>(),
needs_drop::<[String; 2]>(),
needs_drop::<ManuallyDrop<String>>(),
needs_drop::<MaybeUninit<String>>(),
needs_drop::<PhantomData<String>>(),
needs_drop::<Cell<String>>(),
needs_drop::<ByHand>(),
needs_drop::<fn(String)>(),
needs::<String>(),
needs::<u8>(),
needs::<ByHand>(),
needs::<()>(),
needs_drop_of(&named),
needs_drop_of(&copied),
];
out.extend(flags.map(u8::from));
out.push(named() as u8 ^ copied() as u8);
let strings: Vec<String> = data.iter().map(|b| b.to_string()).collect();
out.extend(dropped_by_hand(strings).to_le_bytes());
out.extend(dropped_by_hand(data.to_vec()).to_le_bytes());
for name in [
type_name::<ByHand>(),
type_name::<Option<&[String]>>(),
type_name_of_val(&named),
type_name_of_val(data),
name_of::<u8>(),
name_of::<String>(),
] {
crate::harness::put(out, name);
}
}

/// Whether the value's type needs dropping.
fn needs_drop_of<T>(_: &T) -> bool {
needs_drop::<T>()
}

/// `T`'s name, as a generic body names it.
fn name_of<T: ?Sized>() -> &'static str {
type_name::<T>()
}

/// How many items a generic body drops one by one, as std's collections do only of a type
/// that needs dropping, and forgets the rest.
fn dropped_by_hand<T>(items: Vec<T>) -> u32 {
if !needs_drop::<T>() {
std::mem::forget(items);
return 0;
}
let mut n = 0;
for item in items {
drop(item);
n += 1;
}
n
}
7 changes: 7 additions & 0 deletions ts/src/lower/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2464,6 +2464,13 @@ fn mapping<'tcx>(
let layout = tcx.layout_of(env.as_query_input(targ(gargs, 0))).ok()?;
Expr::lit(layout.align.abi.bytes().to_string())
}
// rustc's answers for the instance, which a JS value that drops nothing, such as a
// `String`'s, leaves as they are.
("mem", "needs_drop") => {
let needs = targ(gargs, 0).needs_drop(tcx, b.t.typing_env_pub());
Expr::lit(needs.to_string())
}
("any", "type_name" | "type_name_of_val") => Expr::Str(rustc_const_eval::util::type_name(tcx, targ(gargs, 0))),
// What wasm32 lays out the value in: its type's, or a slice's elements' or a `str`'s
// bytes'. A trait object's is its vtable's, which is left to the refusal of any other call.
("mem", "size_of_val" | "align_of_val") => {
Expand Down