1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use AllocError;
use Error;
// fn isOomOnlyError(comptime ErrorUnionOrSet: type) bool
//
// Zig's `isOomOnlyError` is pure comptime `@typeInfo` reflection over an
// error set: it iterates the set's members and checks every name == "OutOfMemory".
// Rust has no error-set reflection. The equivalent is encoded structurally in
// the `HandleOom` trait impls below — the `AllocError` impls ARE the
// "OOM-only" arm (Output = T / Output = !), and the `bun_core::Error` impls
// ARE the "other errors possible" arm (Output = Result<T, E> / Output = E).
//
// TODO(port): @typeInfo reflection — no direct Rust equivalent; encoded as trait impls.
/// If `error_union_or_set` is `error.OutOfMemory`, calls `bun.outOfMemory`. Otherwise:
///
/// * If that was the only possible error, returns the non-error payload for error unions, or
/// `noreturn` for error sets.
/// * If other errors are possible, returns the same error union or set, but without
/// `error.OutOfMemory` in the error set.
///
/// Prefer this method over `catch bun.outOfMemory()`, since that could mistakenly catch
/// non-OOM-related errors.
///
/// There are two ways to use this function:
///
/// ```ignore
/// // option 1:
/// let thing = bun::handle_oom(allocate_thing());
/// // option 2:
/// let thing = match allocate_thing() { Ok(v) => v, Err(err) => bun::handle_oom(err) };
/// ```
///
/// PORT NOTE: In Rust, `Vec`/`Box` allocation already aborts on OOM via the
/// global allocator's `handle_alloc_error`. Per PORTING.md §Allocators,
/// callsites of `bun.handleOom(expr)` translate to bare `expr`. This function
/// remains for the residual cases where a `Result<T, AllocError>` is threaded
/// explicitly.
/// Encodes Zig's comptime return-type block (`return_type: { ... }`) of
/// `handleOom`. The Zig branched on `@typeInfo(ArgType)` (error_union vs
/// error_set) and on `isOomOnlyError(ArgType)`; each impl below is one arm of
/// that comptime switch.
// ── .error_union, isOomOnlyError == true → union_info.payload ────────────
// ── .error_set, isOomOnlyError == true → noreturn ────────────────────────
// `!` as an associated type requires nightly; use `core::convert::Infallible`
// (uninhabited) so callers can `match x {}`.
// ── .error_union, mixed error set → same union with OOM subtracted ───────
// Zig computed the narrowed type via
// `@TypeOf(switch (err) { error.OutOfMemory => unreachable, else => |e| e })`.
// Rust error enums are nominal, not sets — there is no set subtraction. For
// the catch-all `bun_core::Error` we compare against the interned tag and
// return the same type. Per-crate `thiserror` enums that carry an
// `OutOfMemory` variant should add their own `HandleOom` impl.
// ── .error_set, mixed → same set with OOM subtracted ─────────────────────
// ported from: src/crash_handler/handle_oom.zig