shape_value/heap_variants.rs
1//! Single source of truth for HeapValue variants.
2//!
3//! `define_heap_types!` generates:
4//! - `HeapValue` enum
5//! - `HeapKind` enum (discriminant)
6//! - `HeapValue::kind()` method
7//! - `HeapValue::is_truthy()` method
8//! - `HeapValue::type_name()` method
9//!
10//! `equals()`, `structural_eq()`, and `Display` remain hand-written because
11//! they have complex per-variant logic (e.g. cross-type numeric comparison).
12//!
13//! Strict-typing bulldozer (Phase 2): every variant whose payload depended on
14//! the deleted `ValueWord` (the v1 dynamic-tag word) has been removed from
15//! `HeapValue`, along with the supporting `*Data` structs. The `HeapKind`
16//! discriminator preserves its ordinal numbering for ABI stability — gone
17//! variants now appear only in `HeapKind` (reserved). Heterogeneous-element
18//! collections (`HashMap`, `Set`, `Deque`, `PriorityQueue`), dynamic
19//! single-value wrappers (`Some`/`Ok`/`Err`/`Range`/`TraitObject`/
20//! `FunctionRef`), and dynamic capture/control-flow holders (`Iterator`,
21//! `Generator`, `Concurrency`, `Rare`, `Enum`, `Array`, `HostClosure`,
22//! `ProjectedRef`) are awaiting monomorphized typed replacements per
23//! `docs/runtime-v2-spec.md`.
24
25/// All HeapValue variant data lives here as a single source of truth.
26///
27/// Because Rust macro hygiene makes it impossible to use identifiers across
28/// macro boundaries (the `_v` in a pattern introduced by one macro cannot be
29/// referenced by tokens captured from a different call site), we define both
30/// the variant table AND the dispatch expressions in the SAME macro.
31///
32/// `define_heap_types!` takes no arguments — the variant table is embedded.
33/// The public types and `impl` blocks are generated inside the expansion.
34///
35/// Callers import this via `crate::define_heap_types!()`.
36#[macro_export]
37macro_rules! define_heap_types {
38 () => {
39 /// Discriminator for HeapValue variants, usable without full pattern match.
40 ///
41 /// One variant per surviving `HeapValue` arm — no dead variants
42 /// expressible. Trimmed in Phase 2b alongside the
43 /// `NativeKind::Ptr(HeapKind)` extension; see
44 /// `docs/defections.md` 2026-05-06 (HeapKind trim +
45 /// NativeKind::Ptr extension) for the audit findings and rejected
46 /// alternatives.
47 ///
48 /// The previous 77-variant surface (with `(removed)` /
49 /// `(deprecated)` annotations) preserved ordinals "for ABI
50 /// stability"; the bulldozer deleted the `tags.rs`
51 /// ordinal-stability test that made that contract load-bearing,
52 /// so the dead variants no longer had a justification to
53 /// remain in the source.
54 ///
55 // ADR-005: HeapKind is the canonical heap-shape discriminator.
56 // Layers above HeapValue take Arc<HeapValue> and dispatch on
57 // HeapValue::kind() rather than introducing parallel discriminators.
58 // See docs/adr/005-typed-slot-construction.md.
59 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ::serde::Serialize, ::serde::Deserialize)]
60 #[repr(u8)]
61 pub enum HeapKind {
62 String, // 0
63 TypedObject, // 1
64 Closure, // 2 (matches HeapValue::ClosureRaw via the Closure ordinal)
65 Decimal, // 3
66 BigInt, // 4
67 DataTable, // 5
68 Future, // 6
69 TaskGroup, // 7
70 TypedArray, // 8 (VACATED: V3-S5 ckpt-1..ckpt-4 (2026-05-15)
71 // retired the `TypedArrayData` enum + outer
72 // `HeapValue::TypedArray(Arc<TypedArrayData>)`
73 // arm + `TypedBuffer<T>` / `AlignedTypedBuffer`
74 // wrapper layer per W12-typed-array-data-
75 // deletion-audit §3.5/§3.6/§B + ADR-006
76 // §2.7.24 Q25.A SUPERSEDED. Ordinal 8 is
77 // vacated; per audit §3.6 deprecation cadence
78 // + handover §0 ordinal-collision rule, the
79 // ordinal MUST NOT be reassigned to a new
80 // HeapKind variant — avoids grep-history
81 // confusion across future agent dispatch.
82 // The variant identifier itself stays in the
83 // enum until V3-S5 ckpt-5 deletes the
84 // 4-table-lockstep dispatch arms (clone_with_kind
85 // / drop_with_kind / SharedCell::drop /
86 // TypedObjectStorage::drop_fields) and the
87 // identifier finally retires. Refusal #1
88 // binding: do not reintroduce under any
89 // rename/shim/bridge.
90 Temporal, // 9
91 TableView, // 10
92 Content, // 11
93 Instant, // 12
94 IoHandle, // 13
95 NativeScalar, // 14
96 NativeView, // 15
97 Char, // 16
98 HashMap, // 17 (Stage C P1(b), 2026-05-07)
99 // Pure-discriminator variant — no corresponding `HeapValue` arm
100 // (FilterExpr payloads live as `Arc<FilterNode>` directly in slot
101 // bits, never wrapped in `HeapValue`). Added to fix the
102 // type-confusion soundness gap surfaced by Wave-α D-raw-helpers
103 // (commit `a27c0e4`): the filter-expression branch of
104 // `executor/logical/mod.rs` previously reused
105 // `HeapKind::NativeView` to label `Arc<FilterNode>` payloads,
106 // and the runtime `clone_with_kind` / `drop_with_kind` tables
107 // dispatched the same label as `Arc<NativeViewData>` —
108 // wrong-type retain/release. ADR-006 §2.3 / §2.7.6 / Q8
109 // amendment (Wave-γ G-heap-filter-expr).
110 FilterExpr, // 18 (Wave-γ G-heap-filter-expr, 2026-05-09)
111 // ADR-006 §2.7.13 / Q14 (Wave 8 W8-T26, 2026-05-10):
112 // Reference-value carrier — replaces the deleted
113 // `nanboxed::RefTarget` / `RefProjection` `ValueWord`-shaped
114 // enum. Slot bits are `Arc::into_raw(Arc<RefTarget>) as u64`
115 // directly (mirror of FilterExpr's pure-discriminator-style
116 // dispatch — `as_heap_value()` is undefined on
117 // Reference-labeled bits; recovery is `Arc::from_raw::
118 // <RefTarget>(bits)`). The `clone_with_kind` /
119 // `drop_with_kind` dispatch tables retain/release
120 // `Arc<RefTarget>` directly, NOT through `HeapValue`. The
121 // `HeapValue::Reference` arm below exists ONLY to preserve
122 // the ADR-005 §1 / ADR-006 §2.3 `HeapKind`↔`HeapValue`
123 // symmetry property; no caller materializes a `Reference`
124 // through `HeapValue` pattern matching.
125 Reference, // 19 (Wave 8 W8-T26, 2026-05-10)
126 // Pure-discriminator variant — no corresponding `HeapValue` arm
127 // (`Arc<SharedCell>` cell-pointer slots live as
128 // `Arc::into_raw(Arc<SharedCell>) as u64` directly in the
129 // kinded stack / module-binding store / cell-storage slots,
130 // never wrapped in `HeapValue`). Added so the §2.7.7 / §2.7.8
131 // parallel-kind tracks can label `*const SharedCell` slots
132 // distinctly — the precondition for unblocking
133 // `op_alloc_shared_local` / `op_alloc_shared_module_binding`.
134 // Same pure-discriminator role as `HeapKind::FilterExpr`:
135 // `as_heap_value()` is unsound on `SharedCell`-labeled bits;
136 // heap dispatch goes through the kind label, not through
137 // `HeapValue` materialisation. ADR-006 §2.7.12 / Q13 amendment
138 // (Wave 8 W8-T25, mirror of §2.7.9 FilterExpr precedent).
139 // NOTE: ordinal 20 (not the originally drafted 19) — T26 took
140 // 19 first at merge time.
141 SharedCell, // 20 (Wave 8 W8-T25, 2026-05-10)
142 // ADR-006 §2.7.15 / Q16 amendment (Wave 13 W13-hashset-rebuild,
143 // 2026-05-10): one-keyspace Set carrier, structurally a mirror
144 // of the Stage C P1(b) `HeapKind::HashMap(Arc<HashMapData>)`
145 // shape with the values buffer dropped. Full HeapValue arm
146 // (NOT pure-discriminator like FilterExpr / SharedCell): Set
147 // values flow through `slot.as_heap_value()` for receiver
148 // classification at method dispatch (`set.add(...)` /
149 // `set.has(...)` / `set.union(other)`), can be stored in
150 // TypedObject slots and `the-deleted-heterogeneous-element-carrier` buffers.
151 // See §2.7.15 for the full justification + the rejected Path
152 // B (`TypedSet<T>` per element kind) alternative.
153 HashSet, // 21 (Wave 13 W13-hashset-rebuild, 2026-05-10)
154 // ADR-006 §2.7.16 / Q17 (W13-iterator-state, 2026-05-10):
155 // Lazy-iterator carrier — replaces the deleted
156 // `heap_value::IteratorState` / `IteratorTransform`
157 // `ValueWord`-shaped enums. Slot bits are
158 // `Arc::into_raw(Arc<IteratorState>) as u64`; unlike
159 // FilterExpr / Reference / SharedCell, the matching
160 // `HeapValue::Iterator(Arc<IteratorState>)` arm IS used at
161 // runtime — iterator method handlers recover the typed Arc
162 // via `slot.as_heap_value()` per ADR-005 §1
163 // single-discriminator. The `clone_with_kind` /
164 // `drop_with_kind` dispatch tables retain/release
165 // `Arc<IteratorState>` directly, NOT through the
166 // `HeapValue` arm (mirror of other typed-Arc
167 // refcount-dispatch arms — refcount discipline goes
168 // through the kind label).
169 Iterator, // 22 (W13-iterator-state, 2026-05-10)
170 // ADR-006 §2.7.19 / Q20 amendment (Wave 15 W15-deque,
171 // 2026-05-10): heterogeneous-element double-ended queue
172 // carrier, structurally a mirror of the §2.7.15 HashSet
173 // shape with the dedup keyspace replaced by a
174 // VecDeque<Arc<HeapValue>>. Full HeapValue arm (NOT
175 // pure-discriminator like FilterExpr / SharedCell): Deque
176 // values flow through `slot.as_heap_value()` for receiver
177 // classification at method dispatch (`d.pushBack(...)` /
178 // `d.popFront()` / `d.size()`). Ordinal 23 (not the
179 // originally drafted 26) — W14 / W15-priority-queue have
180 // not landed at this branch's parent (`bb0ccc3`); per
181 // playbook §0 ordinal-bump rule, the next free slot
182 // after Iterator=22 is taken. Merge ordering at
183 // integration time per playbook §4 (W14 → PriorityQueue
184 // → Deque) restores the documented 26 spec layout.
185 Deque, // 23 (Wave 15 W15-deque, 2026-05-10)
186 // ADR-006 §2.7.20 / Q21 amendment (Wave 15 W15-channel-rebuild,
187 // 2026-05-10): MPSC-style synchronous channel concurrency
188 // primitive. Unlike HashMap/HashSet/Iterator (which are
189 // immutable-on-clone with `Arc::make_mut` clone-on-write),
190 // `ChannelData` carries interior mutability via
191 // `Mutex<ChannelInner>` so two `Arc<ChannelData>` shares of
192 // the same channel observe each other's `send` / `recv`
193 // mutations (the producer/consumer-endpoints shape).
194 // Sync same-thread `send` / `try_recv` / `close` / `is_closed`
195 // land here; blocking `recv()` (cross-task await-style) is
196 // the §2.7.4 task-scheduler boundary and is SURFACE'd at
197 // the method body — see `executor/objects/channel_methods.rs`.
198 // Full HeapValue arm (NOT pure-discriminator) — Channel
199 // values flow through `slot.as_heap_value()` for receiver
200 // classification at method dispatch (`c.send(...)` / `c.recv()`),
201 // can be stored in TypedObject slots and `the-deleted-heterogeneous-element-carrier`
202 // buffers.
203 Channel, // 24 (Wave 15 W15-channel-rebuild, 2026-05-10; bumped from drafted 23 at merge — Deque already took 23)
204 // ADR-006 §2.7.18 / Q19 amendment (Wave 15 W15-priority-queue,
205 // 2026-05-10): i64-priority min-heap carrier, structurally
206 // a mirror of the §2.7.15 HashSet shape with the keys
207 // buffer carrying i64 priorities instead of `Arc<String>`.
208 // Full HeapValue arm (NOT pure-discriminator like FilterExpr
209 // / SharedCell): PriorityQueue values flow through
210 // `slot.as_heap_value()` for receiver classification at
211 // method dispatch (`pq.push(...)` / `pq.pop()` /
212 // `pq.peek()`). See `$crate::heap_value::PriorityQueueData`
213 // for the storage shape and §2.7.18 for the full
214 // justification + the rejected typed-payload alternative.
215 // Pre-assigned ordinal 25 per the wave-14-15-16 playbook
216 // (no bump needed at landing).
217 PriorityQueue, // 25 (Wave 15 W15-priority-queue, 2026-05-10)
218 // W15-range (ADR-006 §2.7.23 / Q24, 2026-05-10): Range value
219 // carrier — `start..end` and `start..=end` surface syntax build
220 // `Arc<RangeData>` slots. Distinct from `HeapKind::Iterator`
221 // (which models the post-`.iter()` stateful pipeline): Range is
222 // a value with identity (`r.start`, `r.contains(x)`, prints as
223 // `0..10`), Iterator is a cursor-bearing pipeline. The
224 // `Range.iter()` receiver method converts `RangeData` to
225 // `IteratorState { source: IteratorSource::Range { start, end,
226 // step } }`, where `IteratorSource::Range` was already provided
227 // by W13-iterator-state for forward compatibility. Full
228 // HeapValue arm (NOT pure-discriminator like FilterExpr /
229 // SharedCell): Range values flow through `slot.as_heap_value()`
230 // for receiver classification at method dispatch.
231 //
232 // Ordinal 30 chosen at W14-15-16 fan-out per the playbook
233 // §0 "Pre-assigned HeapKind ordinals" table. Slots 23 (Result),
234 // 24 (Option), 25 (PriorityQueue), 26 (Deque), 27 (Channel),
235 // 28 (Column), 29 (Matrix) reserved for W14/W15 sibling agents.
236 Range, // 26 (W15-range, 2026-05-10; renumbered from drafted 30 at merge — Result/Option/Column/Matrix slots dissolved or audit-pivoted)
237 // ADR-006 §2.7.17 / Q18 amendment (Wave 14 W14-variant-codegen,
238 // 2026-05-10): Result<T,E> carrier — replaces the deleted
239 // pre-bulldozer `Some/Ok/Err` `ValueWord`-shaped HeapValue
240 // arms. Slot bits are `Arc::into_raw(Arc<ResultData>)`. Full
241 // `HeapValue::Result(Arc<ResultData>)` arm: variant
242 // discriminators (`op_is_ok` / `op_is_err`) and unwrap
243 // operations (`op_unwrap_ok` / `op_unwrap_err` /
244 // `op_try_unwrap`) recover the typed Arc via
245 // `slot.as_heap_value()` per ADR-005 §1 single-discriminator.
246 // Mirror of §2.7.16 Iterator typed-Arc shape (full
247 // HeapValue arm, NOT pure-discriminator like §2.7.9
248 // FilterExpr / §2.7.12 SharedCell).
249 Result, // 27 (Wave 14 W14-variant-codegen, 2026-05-10; renumbered from drafted 23 at merge — Deque already took 23)
250 // ADR-006 §2.7.17 / Q18 amendment (Wave 14 W14-variant-codegen,
251 // 2026-05-10): Option<T> carrier — sibling of Result with
252 // `is_some` discriminator instead of `is_ok`. The dual-shape
253 // representation (vs null-coding `Some(x) ≡ x`, `None ≡ null
254 // sentinel`) is required because `SomeCtor` may take a
255 // null-bearing `T?` payload, which cannot be distinguished
256 // from None under null-coding. Slot bits are
257 // `Arc::into_raw(Arc<OptionData>)`; full HeapValue arm.
258 Option, // 28 (Wave 14 W14-variant-codegen, 2026-05-10; renumbered from drafted 24 at merge — Channel already took 24)
259 // ADR-006 §2.7.24 / Q25.C amendment (Wave 17
260 // W17-trait-object-storage, 2026-05-11): re-introduces the
261 // strict-typing-bulldozer-deleted `HeapKind::TraitObject` /
262 // `HeapValue::TraitObject` carrier as a typed-Arc pair
263 // (`Arc<TraitObjectStorage>`) replacing the legacy
264 // `HeapValue::TraitObject { value: Box<u64>, vtable: Arc<VTable> }`
265 // shape. The new carrier is a fat-pointer over an
266 // `Arc<TypedObjectStorage>` data half + an `Arc<VTable>`
267 // vtable half — universal-dyn auto-boxing (§Q25.C.1) makes
268 // the boxed value always a TypedObject, so the `Box<u64>`
269 // kind-blind raw-bits shape is refused under §Q25.E #3.
270 //
271 // Full HeapValue arm (NOT pure-discriminator like
272 // FilterExpr / SharedCell / Reference): TraitObject values
273 // flow through `slot.as_heap_value()` for receiver
274 // classification at method dispatch (`a.name()` /
275 // `a.clone_me()` etc. — the universe of `dyn T` method
276 // calls). Same dispatch shape as the §2.7.20 Channel
277 // precedent for refcount discipline; `clone_with_kind` /
278 // `drop_with_kind` retain/release
279 // `Arc<TraitObjectStorage>` directly via the kind label,
280 // NOT through `HeapValue`.
281 //
282 // Pre-assigned ordinal 29 per the wave-2.5 W17-trait-object
283 // dispatch contract (the original W17-typed-carrier-mono
284 // playbook reserved 29 for TraitObject; rescope kept that
285 // assignment). Ordinal 29 was free between Option=28 and
286 // the W17-concurrency block Mutex=30 / Atomic=31 / Lazy=32.
287 TraitObject, // 29 (Wave 17 W17-trait-object-storage, 2026-05-11)
288 // ADR-006 §2.7.25 amendment (Wave 17 W17-concurrency,
289 // 2026-05-11): Mutex<T> concurrency primitive — a single
290 // typed payload protected by a `Mutex<MutexInner>` for
291 // interior-mutability sharing (mirror of §2.7.20 Channel's
292 // `Mutex<ChannelInner>` shape — two `Arc<MutexData>` shares
293 // observe each other's `set` mutations). Distinct from
294 // §2.7.12 `HeapKind::SharedCell` (which is binding-storage
295 // interior-mutability for `var` binding-form values) —
296 // `MutexData` is a runtime synchronization primitive user
297 // code asks for explicitly. Full HeapValue arm (NOT
298 // pure-discriminator like FilterExpr / SharedCell): Mutex
299 // values flow through `slot.as_heap_value()` for receiver
300 // classification at method dispatch (`m.lock()` / `m.set(...)`),
301 // can be stored in TypedObject slots. Pre-assigned ordinal
302 // 30 per the wave-2.5 W17-concurrency dispatch contract.
303 Mutex, // 30 (Wave 17 W17-concurrency, 2026-05-11)
304 // ADR-006 §2.7.25 amendment (Wave 17 W17-concurrency,
305 // 2026-05-11): Atomic<i64> concurrency primitive — wraps
306 // `std::sync::atomic::AtomicI64` for atomic load / store /
307 // fetch_add / fetch_sub / compare_exchange operations.
308 // i64-only at landing per the playbook's "typed-payload
309 // deferral" precedent (W15-priority-queue i64-priority-only,
310 // W13-hashset string-only); typed-payload `Atomic<T>` is a
311 // future Phase-2c amendment with measurement. Full HeapValue
312 // arm — Atomic values flow through `slot.as_heap_value()`
313 // for receiver classification at method dispatch.
314 // Pre-assigned ordinal 31 per the wave-2.5 W17-concurrency
315 // dispatch contract.
316 Atomic, // 31 (Wave 17 W17-concurrency, 2026-05-11)
317 // ADR-006 §2.7.25 amendment (Wave 17 W17-concurrency,
318 // 2026-05-11): Lazy<T> initialize-once carrier — wraps an
319 // initializer closure (`KindedSlot` of kind
320 // `Ptr(HeapKind::Closure)`) and a cached value slot.
321 // Closure-call path unlocked by W17-make-closure (merged
322 // at `aa47364`). Mirror of §2.7.20 Channel's
323 // `Mutex<inner>` shape so concurrent `get()` calls
324 // serialize cleanly when the runtime grows real
325 // concurrency. Full HeapValue arm — Lazy values flow
326 // through `slot.as_heap_value()` for receiver
327 // classification at method dispatch (`l.get()` /
328 // `l.is_initialized()`). Pre-assigned ordinal 32 per the
329 // wave-2.5 W17-concurrency dispatch contract.
330 Lazy, // 32 (Wave 17 W17-concurrency, 2026-05-11)
331 // ADR-006 §2.7.26 amendment (Wave 17 W17-comptime-vm-dispatch,
332 // 2026-05-12): module-function reference carrier — labels a
333 // slot whose `bits` are a `module_fn_id: usize` cast to `u64`.
334 // Pure-discriminator variant (no corresponding `HeapValue`
335 // arm); inline-scalar payload (no `Arc<T>`, no heap state) —
336 // same shape as `HeapKind::Future` and `HeapKind::Char`.
337 // `clone_with_kind` / `drop_with_kind` are no-ops on this
338 // arm. Used by `populate_module_objects` to encode the
339 // `__comptime__` (and any other extension) module's typed-
340 // object field references that the compiled bytecode chain
341 // `LoadModuleBinding + GetFieldTyped + CallValue` dispatches
342 // through to `invoke_module_fn_id_stub`. See
343 // `executor/vm_impl/modules.rs::populate_module_objects` for
344 // the construction-side contract and
345 // `executor/call_convention.rs::call_value_immediate_nb`
346 // (`NativeKind::Ptr(HeapKind::ModuleFn)` arm) for the
347 // dispatch-side contract. `as_heap_value()` is unsound on
348 // `ModuleFn`-labeled bits (mirror of FilterExpr /
349 // SharedCell / Reference's pure-discriminator-style
350 // dispatch).
351 ModuleFn, // 33 (Wave 17 W17-comptime-vm-dispatch, 2026-05-12)
352 // ADR-006 §2.7.22 amendment (Round 18 S3
353 // W12-matrix-floatslice-heapkind-exit, 2026-05-13): Matrix exits
354 // the `TypedArrayData` carrier hierarchy. The pre-amendment
355 // Q23 ruling (Matrix lives under `HeapKind::TypedArray` via
356 // `TypedArrayData::Matrix(Arc<MatrixData>)`) is superseded by
357 // the Round 17 deletion-audit + cluster-0-transition
358 // strategic-owner authorization (2026-05-13): Matrix is a
359 // single-Matrix value (category-correctness), not a
360 // buffer-of-Matrix.
361 //
362 // Full `HeapValue::Matrix(Arc<MatrixData>)` arm exists for the
363 // ADR-005 §1 / ADR-006 §2.3 `HeapKind`↔`HeapValue` symmetry,
364 // but Matrix slot bits are
365 // `Arc::into_raw(Arc<MatrixData>) as u64` directly (typed-Arc
366 // shape, mirror of FilterExpr / Reference's pure-discriminator
367 // dispatch — NOT a `Box<HeapValue>` wrap); calling
368 // `slot.as_heap_value()` on a Matrix-labeled slot is
369 // undefined behavior. `clone_with_kind` / `drop_with_kind`
370 // dispatch the matching `Arc::increment/decrement_strong_count
371 // ::<MatrixData>` retain/release directly via the kind label.
372 //
373 // The §2.7.9 / §2.7.12 / §Q23 single-discriminator concern
374 // that motivated Q23's parallel-HeapKind-refusal is addressed
375 // by ADR-005 §1's exception clause: `HeapKind::Matrix` is NOT
376 // parallel to `HeapKind::TypedArray` (which is the
377 // array-buffer carrier with element-typed payload); Matrix is
378 // a separate value category (a structured numeric matrix
379 // value, not an array of anything).
380 Matrix, // 34 (Round 18 S3 W12-matrix-floatslice-heapkind-exit, 2026-05-13)
381 // ADR-006 §2.7.22 amendment (Round 18 S3
382 // W12-matrix-floatslice-heapkind-exit, 2026-05-13): the
383 // `FloatSlice { parent, offset, len }` projection (returned by
384 // `Matrix.row(i)` / `Matrix.col(i)`) exits the
385 // `TypedArrayData` carrier hierarchy for the same
386 // category-correctness reason as `HeapKind::Matrix` — it is a
387 // projection-into-a-Matrix, not a buffer of floats. The new
388 // payload struct is `MatrixSliceData { parent: Arc<MatrixData>,
389 // offset: u32, len: u32 }` preserving the
390 // alias-into-parent-buffer semantics from the pre-amendment
391 // shape.
392 //
393 // Same dispatch shape as `HeapKind::Matrix`: typed-Arc
394 // pure-discriminator (slot bits =
395 // `Arc::into_raw(Arc<MatrixSliceData>)`, retain/release through
396 // the kind label, `as_heap_value()` unsound, full
397 // `HeapValue::MatrixSlice(Arc<MatrixSliceData>)` arm for the
398 // ADR-005 §1 / ADR-006 §2.3 symmetry property).
399 MatrixSlice, // 35 (Round 18 S3 W12-matrix-floatslice-heapkind-exit, 2026-05-13)
400 }
401
402 /// Compact heap-allocated value. Strict-typed variants only — every
403 /// payload is either a typed primitive (`i64`, `char`, `f64` via
404 /// `TypedArray`), a typed structure (`TypedObject` slots, typed FFI
405 /// pointers, typed temporal data), or a typed handle.
406 ///
407 /// Variants whose payloads depended on the deleted `ValueWord`
408 /// dynamic word were removed in the strict-typing Phase-2 bulldozer.
409 /// See the corresponding `HeapKind` ordinals (annotated "(removed)")
410 /// for the migration target.
411 ///
412 // ADR-005: HeapValue is the single discriminator for heap-resident
413 // values. New variants are added here when a new heap shape is
414 // genuinely required; layers above (ConcreteReturn, TypedFieldValue,
415 // marshal helpers, JIT FFI carriers) must NOT introduce parallel
416 // sum types whose variants project 1:1 to HeapKind. The single
417 // explicit exception is `TypedFieldValue::String(Arc<String>)`, named
418 // and bounded in ADR-005. See docs/adr/005-typed-slot-construction.md.
419 // ADR-006 §2.3: each heap-resident variant carries a typed
420 // `Arc<T>` payload (single atomic refcount bump on clone, single
421 // decrement on drop, no `Box<HeapValue>` wrapping). Inline scalars
422 // (`Future(u64)`, `Char(char)`, `NativeScalar`) stay inline because
423 // their payloads fit in a register and have no heap state.
424 // `ClosureRaw` continues to use `OwnedClosureBlock` because that
425 // type already manages its own refcount via the v2 typed-closure
426 // header. See docs/adr/006-value-and-memory-model.md §2.3.
427 #[derive(Debug)]
428 pub enum HeapValue {
429 // ===== Typed primitives =====
430 String(std::sync::Arc<String>),
431 // ADR-006 §2.3: `Decimal` is 16 bytes inline; wrapping in `Arc`
432 // shrinks the enum payload to a pointer so the slot's clone is
433 // a single atomic increment.
434 Decimal(std::sync::Arc<rust_decimal::Decimal>),
435 // ADR-006 §2.3: `BigInt`'s inner `i64` is the v2 placeholder
436 // for an arbitrary-precision integer. Wrapping in `Arc` keeps
437 // the variant cheap to clone today and gives the Drop discipline
438 // a single typed `Arc::decrement_strong_count::<i64>` site for
439 // when the payload widens to a real big-int representation.
440 BigInt(std::sync::Arc<i64>),
441 // Future-id is an inline scalar — no heap state.
442 Future(u64),
443 // Char is an inline scalar — no heap state.
444 Char(char),
445 // ===== Typed handles / data stores =====
446 DataTable(std::sync::Arc<$crate::datatable::DataTable>),
447 // ADR-006 §2.3: `Box<ContentNode>` migrated to `Arc<ContentNode>`
448 // so clones are an atomic refcount bump rather than a deep copy.
449 Content(std::sync::Arc<$crate::content::ContentNode>),
450 // ADR-006 §2.3: `Box<Instant>` migrated to `Arc<Instant>`. The
451 // inner `Instant` is `Copy` but the boxing cost was paid at
452 // every clone; the Arc bump replaces it.
453 Instant(std::sync::Arc<std::time::Instant>),
454 IoHandle(std::sync::Arc<$crate::heap_value::IoHandleData>),
455 // NativeScalar is `Copy` and ≤ 16 bytes — kept inline.
456 NativeScalar($crate::heap_value::NativeScalar),
457 // ADR-006 §2.3: `Box<NativeViewData>` migrated to
458 // `Arc<NativeViewData>` to match `from_native_view(Arc<…>)`.
459 NativeView(std::sync::Arc<$crate::heap_value::NativeViewData>),
460 // ===== Struct variants =====
461 /// Object value with schema-defined typed slots.
462 ///
463 // ADR-006 §2.3: payload was `Arc<TypedObjectStorage>` post the
464 // first §2.3 amendment. Wave 2 Round 4 D4 ckpt-final-prime²
465 // (2026-05-14): payload flipped to `TypedObjectPtr`
466 // (`#[repr(transparent)]` newtype around
467 // `*const TypedObjectStorage`) per the §2.3 amendment + Path B
468 // ratification. The newtype owns one v2-raw HeapHeader-at-offset-0
469 // refcount share; Clone bumps via `v2_retain`, Drop retires via
470 // `TypedObjectStorage::release_elem`. Auto-derived Drop/Clone/
471 // Send/Sync on `HeapValue` chain through the wrapper's manual
472 // discipline. See docs/adr/006-value-and-memory-model.md §2.3.
473 TypedObject($crate::heap_value::TypedObjectPtr),
474 /// Track A.5 — the canonical closure representation.
475 ///
476 /// Raw `TypedClosureHeader`-backed closure. Captures live in a
477 /// typed C-laid-out block allocated by
478 /// `closure_raw::alloc_typed_closure` and owned by the embedded
479 /// [`OwnedClosureBlock`]. Cloning / dropping this variant
480 /// manages the block's refcount in lockstep with the enclosing
481 /// `Arc<HeapValue>`. Readers go through `VmClosureHandle` for
482 /// the stable read API. There is no legacy fallback.
483 ClosureRaw($crate::v2::closure_raw::OwnedClosureBlock),
484 // ADR-006 §2.3: `TaskGroup { kind, task_ids }` struct variant
485 // collapsed to a single-tuple `Arc<TaskGroupData>` payload so
486 // every heap variant follows the typed-Arc shape. Field reads
487 // are now `tg.kind` / `tg.task_ids` (Phase 1.B caller migration).
488 TaskGroup(std::sync::Arc<$crate::heap_value::TaskGroupData>),
489 // ===== Consolidated wrapper variants =====
490 // V3-S5 ckpt-4 (2026-05-15): `TypedArray(Arc<TypedArrayData>)`
491 // arm DELETED. The inner `TypedArrayData` enum was retired at
492 // V3-S5 ckpt-1 (heap_value.rs:2877-3052 wholesale deletion per
493 // W12-typed-array-data-deletion-audit §3.5 / §B + ADR-006
494 // §2.7.24 Q25.A SUPERSEDED). With no inner payload to wrap,
495 // the outer `HeapValue::TypedArray(...)` arm is now orphan and
496 // is deleted in lockstep. The `HeapKind::TypedArray = 8`
497 // ordinal becomes a "vacated ordinal" comment marker (see the
498 // HeapKind table earlier in this file). 4-table-lockstep
499 // dispatch arms for `HeapKind::TypedArray` (clone_with_kind /
500 // drop_with_kind / SharedCell::drop /
501 // TypedObjectStorage::drop_fields) are deleted at V3-S5 ckpt-5
502 // territory per supervisor 2026-05-15 partition.
503 //
504 // Refusal #1 binding: do not resurrect this arm under any
505 // rename/shim/bridge — see CLAUDE.md "Forbidden code" +
506 // "Renames to refuse on sight" broader-family regex.
507 // ADR-006 §2.3: `TemporalData` enum was inline (size = largest
508 // variant ≈ 32 bytes including `Box`'s overhead). `Arc` reduces
509 // the slot payload to a single pointer.
510 Temporal(std::sync::Arc<$crate::heap_value::TemporalData>),
511 // ADR-006 §2.3: `TableViewData` enum migrated to `Arc<…>` to
512 // match the canonical typed-Arc shape; its arms already carry
513 // `Arc<DataTable>` internally.
514 TableView(std::sync::Arc<$crate::heap_value::TableViewData>),
515 // ===== Stage C HashMap-marshal P1(b) =====
516 /// HashMap with string keys + per-V monomorphized values.
517 ///
518 /// **Wave 2 Round 3b C2-joint ckpt-2 (2026-05-14):** payload flipped
519 /// from `Arc<HashMapData>` (non-generic) to `HashMapKindedRef`
520 /// (per-V enum carrier) per ADR-006 §2.7.24 Q25.B SUPERSEDED +
521 /// audit §C.4 option (a.2). The variant tag IS the per-V
522 /// `NativeKind` discriminator; per-V dispatch at consumer sites
523 /// goes through the `HashMapKindedRef::{I64, F64, Bool, Char,
524 /// String, Decimal, TypedObject, TraitObject}` arms.
525 ///
526 /// See `$crate::heap_value::HashMapData<V>` + `HashMapKindedRef`
527 /// for the storage shape. Stage C P1(b), 2026-05-07.
528 HashMap($crate::heap_value::HashMapKindedRef),
529 // ===== Wave-γ G-heap-filter-expr (2026-05-09) =====
530 /// Filter-expression tree (`Arc<FilterNode>`) used by the query
531 /// DSL's `And` / `Or` / `Not` opcodes (`executor/logical/mod.rs`).
532 /// In current code FilterExpr payloads are emitted directly to
533 /// the kinded stack as `Arc::into_raw(Arc<FilterNode>) as u64`
534 /// with kind `NativeKind::Ptr(HeapKind::FilterExpr)` and never
535 /// wrapped in `HeapValue`. The arm exists to preserve the
536 /// ADR-005 §1 invariant that every `HeapKind` discriminator has
537 /// a `HeapValue` arm of the same shape — kind() / is_truthy() /
538 /// type_name() / drop_with_kind() / clone_with_kind() must
539 /// dispatch a `HeapKind::FilterExpr` slot as `Arc<FilterNode>`,
540 /// not `Arc<NativeViewData>` (the pre-Wave-γ type-confusion gap
541 /// surfaced by Wave-α D-raw-helpers, commit `a27c0e4`).
542 FilterExpr(std::sync::Arc<$crate::value::FilterNode>),
543 // ===== Wave 13 W13-hashset-rebuild (ADR-006 §2.7.15 / Q16,
544 // 2026-05-10) =====
545 /// One-keyspace Set carrier. Mirror of
546 /// `HeapValue::HashMap(Arc<HashMapData>)` with the values
547 /// buffer dropped: insertion-ordered `Arc<TypedBuffer<Arc<
548 /// String>>>` keys + eager FNV-1a bucket index for O(1)
549 /// `set.has(key)`. See `$crate::heap_value::HashSetData` for
550 /// the storage shape.
551 ///
552 /// Full HeapValue arm (NOT pure-discriminator like FilterExpr
553 /// / SharedCell): Set values flow through `as_heap_value()`
554 /// for method-receiver classification per the §2.7.15 amendment.
555 HashSet(std::sync::Arc<$crate::heap_value::HashSetData>),
556 // ===== Wave 8 W8-T26 (ADR-006 §2.7.13 / Q14, 2026-05-10) =====
557 /// Reference-value carrier (`Arc<RefTarget>`) used by the
558 /// `MakeRef` / `MakeFieldRef` / `MakeIndexRef` /
559 /// `DerefLoad` / `DerefStore` / `SetIndexRef` opcode family
560 /// (`executor/variables/mod.rs`). In current code Reference
561 /// payloads are emitted directly to the kinded stack as
562 /// `Arc::into_raw(Arc<RefTarget>) as u64` with kind
563 /// `NativeKind::Ptr(HeapKind::Reference)` and never wrapped
564 /// in `HeapValue`. The arm exists to preserve the ADR-005
565 /// §1 / ADR-006 §2.3 `HeapKind`↔`HeapValue` symmetry — same
566 /// pattern as `HeapValue::FilterExpr` (§2.7.9). Calling
567 /// `slot.as_heap_value()` on a Reference-labeled slot is
568 /// undefined behavior; the canonical recovery is
569 /// `Arc::from_raw::<RefTarget>(bits)`.
570 Reference(std::sync::Arc<$crate::reference::RefTarget>),
571 // ===== W13-iterator-state (ADR-006 §2.7.16 / Q17, 2026-05-10) =====
572 /// Lazy iterator pipeline carrier (`Arc<IteratorState>`).
573 /// Used by `Array.iter` / `String.iter` / `HashMap.iter` /
574 /// `Range.iter` factories and the `ITERATOR_METHODS` PHF
575 /// (`map` / `filter` / `take` / `skip` / `flatMap` /
576 /// `enumerate` / `chain` / `collect` / `forEach` /
577 /// `reduce` / `count` / `any` / `all` / `find`). Slot bits
578 /// are `Arc::into_raw(Arc<IteratorState>) as u64`; recovery
579 /// goes through `slot.as_heap_value()` →
580 /// `HeapValue::Iterator(arc)` per ADR-005 §1
581 /// single-discriminator (the lazy-transforms / source /
582 /// cursor triple is opaque at the dispatch shell —
583 /// terminals walk `arc.transforms` and dispatch per stage).
584 Iterator(std::sync::Arc<$crate::iterator_state::IteratorState>),
585 // ===== Wave 15 W15-deque (ADR-006 §2.7.19 / Q20, 2026-05-10) =====
586 /// Double-ended queue carrier. Structurally a mirror of
587 /// `HeapValue::HashSet(Arc<HashSetData>)` with the dedup
588 /// keyspace replaced by a `VecDeque<Arc<HeapValue>>`
589 /// (heterogeneous-element, order-preserving, no
590 /// deduplication). See `$crate::heap_value::DequeData` for
591 /// the storage shape.
592 ///
593 /// Full HeapValue arm (NOT pure-discriminator like
594 /// FilterExpr / SharedCell): Deque values flow through
595 /// `as_heap_value()` for receiver classification per the
596 /// §2.7.19 amendment.
597 Deque(std::sync::Arc<$crate::heap_value::DequeData>),
598 // ===== Wave 15 W15-channel-rebuild (ADR-006 §2.7.20 / Q21,
599 // 2026-05-10) =====
600 /// MPSC-style synchronous channel carrier (`Arc<ChannelData>`).
601 /// Unlike HashMap/HashSet (immutable-on-clone with
602 /// `Arc::make_mut` clone-on-write), `ChannelData` wraps a
603 /// `Mutex<ChannelInner>` so two `Arc<ChannelData>` shares
604 /// of the same channel observe each other's `send` /
605 /// `recv` mutations — the producer/consumer-endpoints
606 /// shape. See `$crate::heap_value::ChannelData` for the
607 /// storage shape and the §2.7.20 amendment for the design
608 /// rationale.
609 ///
610 /// Full HeapValue arm (NOT pure-discriminator like FilterExpr
611 /// / SharedCell): Channel values flow through
612 /// `slot.as_heap_value()` for receiver classification at
613 /// method dispatch — same shape as `HashSet` / `Iterator`.
614 Channel(std::sync::Arc<$crate::heap_value::ChannelData>),
615 // ===== Wave 15 W15-priority-queue (ADR-006 §2.7.18 / Q19,
616 // 2026-05-10) =====
617 /// Min-heap-backed PriorityQueue carrier. Mirror of
618 /// `HeapValue::HashSet(Arc<HashSetData>)` with the keys
619 /// buffer carrying i64 priorities instead of `Arc<String>`:
620 /// `Arc<TypedBuffer<i64>>` heap-ordered values (root = min).
621 /// See `$crate::heap_value::PriorityQueueData` for the
622 /// storage shape.
623 ///
624 /// Full HeapValue arm (NOT pure-discriminator like FilterExpr
625 /// / SharedCell): PriorityQueue values flow through
626 /// `as_heap_value()` for method-receiver classification per
627 /// the §2.7.18 amendment.
628 ///
629 /// **i64-priority-only at landing** per the §2.7.18 Q19
630 /// ruling (typed-payload `PriorityQueue<T, K>` with
631 /// key-extractor is a future Phase-2c amendment with
632 /// measurement; the smoke target is exercised on this
633 /// shape).
634 PriorityQueue(std::sync::Arc<$crate::heap_value::PriorityQueueData>),
635 // ===== W15-range (ADR-006 §2.7.23 / Q24, 2026-05-10) =====
636 /// Range value carrier (`Arc<RangeData>`). Built by
637 /// `MakeRange` from the `start..end` / `start..=end` surface
638 /// syntax. Slot bits are `Arc::into_raw(Arc<RangeData>) as
639 /// u64` (typed-Arc shape, mirror of HashMap / HashSet /
640 /// Iterator). Recovery goes through `slot.as_heap_value()`
641 /// → `HeapValue::Range(arc)` for receiver classification at
642 /// method dispatch (`r.contains(x)` / `r.toArray()` /
643 /// `r.iter()`). Same dispatch shape as the FilterExpr §2.7.9
644 /// amendment for refcount discipline (clone_with_kind /
645 /// drop_with_kind retain/release `Arc<RangeData>` directly,
646 /// NOT through `HeapValue`).
647 Range(std::sync::Arc<$crate::heap_value::RangeData>),
648 // ===== Wave 14 W14-variant-codegen (ADR-006 §2.7.17 / Q18,
649 // 2026-05-10) =====
650 /// Result<T, E> carrier (`Arc<ResultData>`). Used by the
651 /// `OkCtor` / `ErrCtor` builtin producers and the
652 /// `op_is_ok` / `op_is_err` / `op_unwrap_ok` /
653 /// `op_unwrap_err` / `op_try_unwrap` discriminators.
654 /// Slot bits are `Arc::into_raw(Arc<ResultData>) as u64`;
655 /// recovery goes through `slot.as_heap_value()` →
656 /// `HeapValue::Result(arc)` per ADR-005 §1
657 /// single-discriminator. The inner `payload: KindedSlot`
658 /// owns one strong-count share for the wrapped value;
659 /// `ResultData::Drop` (auto-derived from `KindedSlot`'s
660 /// explicit Drop) retires the share at refcount=0.
661 Result(std::sync::Arc<$crate::heap_value::ResultData>),
662 /// Option<T> carrier (`Arc<OptionData>`). Used by the
663 /// `SomeCtor` builtin producer and the `op_unwrap_option`
664 /// discriminator (the `None` half is also constructed as
665 /// `OptionData::none()` at compiler emission sites). Same
666 /// kinded-payload discipline as `Result` per §2.7.17.
667 Option(std::sync::Arc<$crate::heap_value::OptionData>),
668 // ===== W17-trait-object-storage (ADR-006 §2.7.24 / Q25.C,
669 // 2026-05-11) =====
670 /// `dyn Trait` carrier (`Arc<TraitObjectStorage>`).
671 /// Re-introduces the bulldozer-deleted `HeapValue::TraitObject`
672 /// arm as a typed-Arc pair — `TraitObjectStorage` holds an
673 /// `Arc<TypedObjectStorage>` data half + an `Arc<VTable>`
674 /// vtable half. Slot bits are
675 /// `Arc::into_raw(Arc<TraitObjectStorage>) as u64`;
676 /// recovery goes through `slot.as_heap_value()` →
677 /// `HeapValue::TraitObject(arc)` per ADR-005 §1
678 /// single-discriminator. The compiler-emission tier
679 /// (W17-trait-object-emission round) populates the slot
680 /// via `OpCode::BoxTraitObject` and dispatches method
681 /// calls via `OpCode::DynMethodCall` against the recovered
682 /// trait-object carrier. See ADR-006 §2.7.24 Q25.C.1
683 /// (universal-dyn auto-boxing), Q25.C.2 (Self-arg runtime
684 /// vtable-identity check), Q25.C.3 (generic-method
685 /// TypeInfo dispatch), Q25.C.5 (`VTableEntry` 6-variant
686 /// shape).
687 ///
688 /// **Wave 2 Round 4 D4 ckpt-final-prime² (2026-05-14): payload
689 /// flipped from `Arc<TraitObjectStorage>` to `TraitObjectPtr`**
690 /// (`#[repr(transparent)]` newtype around
691 /// `*const TraitObjectStorage`) per the §Q25.C.5 amendment +
692 /// Path B ratification. Mirror of the TypedObject flip in the
693 /// same commit — the newtype owns one v2-raw HeapHeader-at-
694 /// offset-0 refcount share; Clone via `v2_retain`, Drop via
695 /// `TraitObjectStorage::release_elem`.
696 TraitObject($crate::heap_value::TraitObjectPtr),
697 // ===== W17-concurrency (ADR-006 §2.7.25, 2026-05-11) =====
698 /// `Mutex<T>` concurrency-primitive carrier
699 /// (`Arc<MutexData>`). The inner `MutexData` wraps a
700 /// `Mutex<MutexInner>` so two `Arc<MutexData>` shares of
701 /// the same mutex observe each other's `set` mutations —
702 /// the same interior-mutability shape as
703 /// `HeapValue::Channel`. Full HeapValue arm — Mutex values
704 /// flow through `slot.as_heap_value()` for receiver
705 /// classification at method dispatch.
706 Mutex(std::sync::Arc<$crate::heap_value::MutexData>),
707 /// `Atomic<i64>` concurrency-primitive carrier
708 /// (`Arc<AtomicData>`). The inner `AtomicData` wraps a
709 /// `std::sync::atomic::AtomicI64` for atomic load / store /
710 /// fetch_add / fetch_sub / compare_exchange. i64-only at
711 /// landing per ADR-006 §2.7.25 — typed-payload `Atomic<T>`
712 /// is a future Phase-2c amendment with measurement.
713 Atomic(std::sync::Arc<$crate::heap_value::AtomicData>),
714 /// `Lazy<T>` initialize-once carrier (`Arc<LazyData>`).
715 /// Wraps an initializer closure and cached value slot.
716 /// Closure-call path is unlocked by W17-make-closure
717 /// (merged at `aa47364`). Full HeapValue arm.
718 Lazy(std::sync::Arc<$crate::heap_value::LazyData>),
719 // ===== W17-comptime-vm-dispatch (ADR-006 §2.7.26, 2026-05-12) =====
720 /// Module-function reference inline-scalar carrier — labels
721 /// a slot whose bits decode to a `module_fn_id: u64` indexing
722 /// `VirtualMachine.module_fn_table`. Inline-scalar payload
723 /// (no `Arc<T>`, no heap state) — same shape as
724 /// `HeapValue::Future(u64)` / `HeapValue::Char(char)`.
725 ///
726 /// Pure-discriminator pattern: in current code ModuleFn
727 /// payloads are emitted directly to the kinded stack /
728 /// TypedObject slot as `module_fn_id as u64` with kind
729 /// `NativeKind::Ptr(HeapKind::ModuleFn)` and never wrapped
730 /// in `HeapValue`. The arm exists to preserve the ADR-005
731 /// §1 / ADR-006 §2.3 `HeapKind`↔`HeapValue` symmetry — same
732 /// pattern as `HeapValue::FilterExpr` (§2.7.9) /
733 /// `HeapValue::Reference` (§2.7.13). Calling
734 /// `slot.as_heap_value()` on a ModuleFn-labeled slot is
735 /// undefined behavior; the canonical recovery is reading
736 /// the raw `u64` bits as the `module_fn_id`.
737 ModuleFn(u64),
738 // ===== Round 18 S3 W12-matrix-floatslice-heapkind-exit
739 // (ADR-006 §2.7.22 amendment, 2026-05-13) =====
740 /// Matrix value carrier (`Arc<MatrixData>`). Built by
741 /// `op_new_matrix` from the `matrix(rows, cols, [data...])`
742 /// surface form. In current code Matrix payloads are emitted
743 /// directly to the kinded stack / TypedObject slot as
744 /// `Arc::into_raw(Arc<MatrixData>) as u64` with kind
745 /// `NativeKind::Ptr(HeapKind::Matrix)` and never wrapped in
746 /// `HeapValue`. The arm exists to preserve the ADR-005 §1 /
747 /// ADR-006 §2.3 `HeapKind`↔`HeapValue` symmetry — same
748 /// pattern as `HeapValue::FilterExpr` (§2.7.9) /
749 /// `HeapValue::Reference` (§2.7.13). Calling
750 /// `slot.as_heap_value()` on a Matrix-labeled slot is
751 /// undefined behavior; the canonical recovery is
752 /// `Arc::<MatrixData>::from_raw(bits)`.
753 Matrix(std::sync::Arc<$crate::heap_value::MatrixData>),
754 /// Matrix-projection carrier (`Arc<MatrixSliceData>`). Built
755 /// by `Matrix.row(i)` / `Matrix.col(i)` from a parent matrix.
756 /// `MatrixSliceData { parent: Arc<MatrixData>, offset, len }`
757 /// preserves the aliasing-into-parent semantics from the
758 /// pre-amendment `TypedArrayData::FloatSlice` shape. Same
759 /// typed-Arc pure-discriminator dispatch shape as
760 /// `HeapValue::Matrix`.
761 MatrixSlice(std::sync::Arc<$crate::heap_value::MatrixSliceData>),
762 }
763
764 impl HeapValue {
765 /// Get the kind discriminator for fast dispatch without full pattern matching.
766 #[inline]
767 pub fn kind(&self) -> HeapKind {
768 match self {
769 HeapValue::String(..) => HeapKind::String,
770 HeapValue::Decimal(..) => HeapKind::Decimal,
771 HeapValue::BigInt(..) => HeapKind::BigInt,
772 HeapValue::Future(..) => HeapKind::Future,
773 HeapValue::Char(..) => HeapKind::Char,
774 HeapValue::DataTable(..) => HeapKind::DataTable,
775 HeapValue::Content(..) => HeapKind::Content,
776 HeapValue::Instant(..) => HeapKind::Instant,
777 HeapValue::IoHandle(..) => HeapKind::IoHandle,
778 HeapValue::NativeScalar(..) => HeapKind::NativeScalar,
779 HeapValue::NativeView(..) => HeapKind::NativeView,
780 HeapValue::TypedObject(..) => HeapKind::TypedObject,
781 HeapValue::ClosureRaw(..) => HeapKind::Closure,
782 HeapValue::TaskGroup(..) => HeapKind::TaskGroup,
783 // V3-S5 ckpt-4: `HeapValue::TypedArray(..)` kind arm
784 // deleted in lockstep with the variant + the
785 // TypedArrayData enum (ckpt-1) + wrapper layer (ckpt-4).
786 // `HeapKind::TypedArray = 8` ordinal is vacated (see
787 // ordinal table above) but the identifier stays until
788 // ckpt-5 4-table-lockstep deletion.
789 HeapValue::Temporal(..) => HeapKind::Temporal,
790 HeapValue::TableView(..) => HeapKind::TableView,
791 HeapValue::HashMap(..) => HeapKind::HashMap,
792 HeapValue::HashSet(..) => HeapKind::HashSet,
793 HeapValue::FilterExpr(..) => HeapKind::FilterExpr,
794 HeapValue::Reference(..) => HeapKind::Reference,
795 HeapValue::Iterator(..) => HeapKind::Iterator,
796 HeapValue::Deque(..) => HeapKind::Deque,
797 HeapValue::Channel(..) => HeapKind::Channel,
798 HeapValue::PriorityQueue(..) => HeapKind::PriorityQueue,
799 HeapValue::Range(..) => HeapKind::Range,
800 HeapValue::Result(..) => HeapKind::Result,
801 HeapValue::Option(..) => HeapKind::Option,
802 HeapValue::TraitObject(..) => HeapKind::TraitObject,
803 HeapValue::Mutex(..) => HeapKind::Mutex,
804 HeapValue::Atomic(..) => HeapKind::Atomic,
805 HeapValue::Lazy(..) => HeapKind::Lazy,
806 HeapValue::ModuleFn(..) => HeapKind::ModuleFn,
807 HeapValue::Matrix(..) => HeapKind::Matrix,
808 HeapValue::MatrixSlice(..) => HeapKind::MatrixSlice,
809 }
810 }
811
812 /// Check if this heap value is truthy.
813 #[inline]
814 pub fn is_truthy(&self) -> bool {
815 match self {
816 HeapValue::String(_v) => !_v.is_empty(),
817 HeapValue::Decimal(_v) => !_v.is_zero(),
818 HeapValue::BigInt(_v) => **_v != 0,
819 HeapValue::Future(_) => true,
820 HeapValue::Char(_) => true,
821 HeapValue::DataTable(_v) => _v.row_count() > 0,
822 HeapValue::Content(_) => true,
823 HeapValue::Instant(_) => true,
824 HeapValue::IoHandle(_v) => _v.is_open(),
825 HeapValue::NativeScalar(_v) => _v.is_truthy(),
826 HeapValue::NativeView(_v) => _v.ptr != 0,
827 HeapValue::TypedObject(s) => !s.slots.is_empty(),
828 HeapValue::ClosureRaw(..) => true,
829 HeapValue::TaskGroup(..) => true,
830 // V3-S5 ckpt-4: `HeapValue::TypedArray(ta) => ta.is_truthy()`
831 // arm deleted in lockstep with the variant + the
832 // `TypedArrayData::is_truthy` impl (ckpt-1 wholesale deletion).
833 HeapValue::Temporal(td) => td.is_truthy(),
834 HeapValue::TableView(tv) => tv.is_truthy(),
835 HeapValue::HashMap(d) => !d.is_empty(),
836 HeapValue::HashSet(d) => !d.is_empty(),
837 // Filter-expression trees are always truthy when present.
838 HeapValue::FilterExpr(_) => true,
839 // Reference values are always truthy when present
840 // (a live ref points at a reachable place).
841 HeapValue::Reference(_) => true,
842 // Iterator values are always truthy when present
843 // (a live iterator is a usable pipeline value, even
844 // if its terminal evaluation will yield zero
845 // elements after filter / take 0 etc.).
846 HeapValue::Iterator(_) => true,
847 // Wave 15 W15-deque (ADR-006 §2.7.19 / Q20):
848 // truthy iff the deque has at least one element.
849 HeapValue::Deque(d) => !d.is_empty(),
850 // Channel values are always truthy when present
851 // (a live channel is a usable endpoint regardless of
852 // queued-element count or closed state).
853 HeapValue::Channel(_) => true,
854 // Wave 15 W15-priority-queue (ADR-006 §2.7.18 / Q19,
855 // 2026-05-10): empty PQ is falsy, non-empty is
856 // truthy — mirror of the HashSet / HashMap shape.
857 HeapValue::PriorityQueue(d) => !d.is_empty(),
858 // Empty range (zero elements) is falsy; non-empty is
859 // truthy. Mirrors the HashSet/HashMap "empty is
860 // falsy" pattern at §2.7.15. Cheap O(1) check via
861 // `RangeData::is_empty()`.
862 HeapValue::Range(r) => !r.is_empty(),
863 // Result and Option are always truthy when present
864 // (a wrapper's variant tag is a runtime contract;
865 // truthiness reflects "carrier exists" not the
866 // inner success/none state). Inner-aware boolean
867 // tests go through `op_is_ok` / `op_is_err`.
868 HeapValue::Result(_) => true,
869 HeapValue::Option(_) => true,
870 // W17-trait-object-storage (ADR-006 §2.7.24 / Q25.C,
871 // 2026-05-11): a `dyn Trait` carrier is always
872 // truthy when present — a boxed trait object is a
873 // live receiver regardless of its inner value.
874 // Same shape as Reference / Iterator / Channel.
875 HeapValue::TraitObject(_) => true,
876 // W17-concurrency (ADR-006 §2.7.25, 2026-05-11):
877 // concurrency primitives are always truthy when
878 // present — a live mutex/atomic/lazy is a usable
879 // synchronisation handle regardless of inner state.
880 // Same shape as Channel / Iterator / Reference.
881 HeapValue::Mutex(_) => true,
882 HeapValue::Atomic(_) => true,
883 HeapValue::Lazy(_) => true,
884 // ModuleFn references are always truthy when present
885 // (a live module-fn-id is a usable callable handle).
886 HeapValue::ModuleFn(_) => true,
887 // ADR-006 §2.7.22 amendment (Round 18 S3, 2026-05-13):
888 // truthy iff the underlying flat buffer / projection
889 // length is non-empty, mirroring the pre-amendment
890 // `TypedArrayData::Matrix` / `FloatSlice` is_truthy
891 // shape.
892 HeapValue::Matrix(m) => m.data.len() > 0,
893 HeapValue::MatrixSlice(s) => s.len > 0,
894 }
895 }
896
897 /// Get the type name for this heap value.
898 #[inline]
899 pub fn type_name(&self) -> &'static str {
900 match self {
901 HeapValue::String(_) => "string",
902 HeapValue::Decimal(_) => "decimal",
903 HeapValue::BigInt(_) => "int",
904 HeapValue::Future(_) => "future",
905 HeapValue::Char(_) => "char",
906 HeapValue::DataTable(_) => "datatable",
907 HeapValue::Content(_) => "content",
908 HeapValue::Instant(_) => "instant",
909 HeapValue::IoHandle(_) => "io_handle",
910 HeapValue::NativeScalar(v) => v.type_name(),
911 HeapValue::NativeView(v) => {
912 if v.mutable {
913 "cmut"
914 } else {
915 "cview"
916 }
917 }
918 HeapValue::TypedObject(..) => "object",
919 HeapValue::ClosureRaw(..) => "closure",
920 HeapValue::TaskGroup(..) => "task_group",
921 // V3-S5 ckpt-4: `HeapValue::TypedArray(ta) => ta.type_name()`
922 // arm deleted in lockstep with the variant + the
923 // `TypedArrayData::type_name` impl (ckpt-1 wholesale deletion).
924 HeapValue::Temporal(td) => td.type_name(),
925 HeapValue::TableView(tv) => tv.type_name(),
926 HeapValue::HashMap(_) => "hashmap",
927 HeapValue::HashSet(_) => "hashset",
928 HeapValue::FilterExpr(_) => "filter_expr",
929 HeapValue::Reference(_) => "ref",
930 HeapValue::Iterator(_) => "iterator",
931 HeapValue::Deque(_) => "deque",
932 HeapValue::Channel(_) => "channel",
933 HeapValue::PriorityQueue(_) => "priority_queue",
934 HeapValue::Range(_) => "range",
935 HeapValue::Result(_) => "result",
936 HeapValue::Option(_) => "option",
937 HeapValue::TraitObject(_) => "trait_object",
938 HeapValue::Mutex(_) => "mutex",
939 HeapValue::Atomic(_) => "atomic",
940 HeapValue::Lazy(_) => "lazy",
941 HeapValue::ModuleFn(_) => "module_fn",
942 // ADR-006 §2.7.22 amendment (Round 18 S3, 2026-05-13).
943 HeapValue::Matrix(_) => "matrix",
944 HeapValue::MatrixSlice(_) => "matrix_slice",
945 }
946 }
947 }
948 };
949}