Skip to main content

shape_value/
kinded_slot.rs

1//! `KindedSlot`: caller-side runtime-value carrier (ADR-006 §2.7 / Q7).
2//!
3//! Pairs a raw 8-byte `ValueSlot` with the `NativeKind` that interprets its
4//! bits. Used at GENERIC_CARRIER sites — module bindings, frame info,
5//! suspension state, intrinsic dispatch, output adapters — where the kind
6//! is **not** statically determined by the surrounding `FieldType` /
7//! schema. STATIC_KIND sites continue to use `ValueSlot` directly.
8//!
9//! ## Why a struct, not a sum type
10//!
11//! ADR-005 §1's single-discriminator discipline forbids parallel sum types
12//! whose variants project 1:1 to `HeapKind`. `KindedSlot` is a *struct*, not
13//! a sum type — the kind is data, not a discriminator. `NativeKind` is also
14//! broader than `HeapKind` (it includes raw scalars `Int64`/`Float64`/`Bool`
15//! with no `HeapValue` arm). The kind→heap mapping is many-to-one (heap
16//! arms only), not 1:1.
17//!
18//! ## Why explicit `Drop` / `Clone`, NOT `Copy`
19//!
20//! `ValueSlot` itself is `Copy` (it's a raw `u64`). Putting `KindedSlot` in
21//! a `Vec` would alias-copy the heap pointer on every `push`/`pop`/`clone`
22//! and the default `Vec::drop` would leak refcounts (or, after a clone,
23//! double-free them on the second drop). This is the WB2.4 / WB2.5 bug
24//! class the typed-slot ABI was designed to prevent.
25//!
26//! The reference precedent is `TypedObjectStorage::Drop` in
27//! `heap_value.rs:761-889`: walk a per-slot `NativeKind`, dispatch to the
28//! matching `Arc::decrement_strong_count::<T>`. This module mirrors that
29//! discipline at the carrier-struct level.
30//!
31//! ## Forbidden uses (ADR-006 §2.7.2)
32//!
33//! - Do not use `KindedSlot` where `NativeKind` is statically known
34//!   (would re-introduce kind-tag latency the slot ABI just removed).
35//! - Do not introduce `KindedSlot` *variants* (sum-type form).
36//! - Do not let `KindedSlot` leak into the typed VM↔JIT slot ABI
37//!   (`docs/runtime-v2-spec.md`). The hot stack/JIT path stays
38//!   `ValueSlot`-only with kind threaded through opcodes.
39//!
40//! See `docs/adr/006-value-and-memory-model.md` §2.7.
41
42// ADR-006 §2.7
43// V3-S5 ckpt-4 (2026-05-15): `TypedArrayData` import deleted — the enum
44// was retired at ckpt-1 per W12-typed-array-data-deletion-audit §3.5 +
45// ADR-006 §2.7.24 Q25.A SUPERSEDED. `from_typed_array(Arc<TypedArrayData>)`
46// convenience constructor deleted in lockstep below. The 4-table-lockstep
47// dispatch arms for `HeapKind::TypedArray` in this file's clone/drop
48// dispatch tables (lines ~690 / ~1045 pre-edit) stay until V3-S5 ckpt-5
49// per supervisor 2026-05-15 partition (ckpt-5 territory: 4-table lockstep
50// deletion + U64 relabel + A1 fold).
51use crate::heap_value::{
52    AtomicData, ChannelData, DequeData, HashMapData, HashSetData, HeapKind, HeapValue,
53    IoHandleData, LazyData, MatrixData, MatrixSliceData, MutexData, NativeViewData, OptionData,
54    PriorityQueueData, RangeData, ResultData, TableViewData, TaskGroupData, TemporalData,
55    TraitObjectStorage, TypedObjectStorage,
56};
57use crate::iterator_state::IteratorState;
58use crate::native_kind::NativeKind;
59use crate::reference::RefTarget;
60use crate::slot::ValueSlot;
61use crate::value::FilterNode;
62use std::sync::Arc;
63
64/// Caller-side runtime-value carrier: a `ValueSlot` paired with the
65/// `NativeKind` that interprets it. ADR-006 §2.7.
66///
67/// **Not `Copy`.** Drop and clone dispatch on `kind` to manage heap
68/// refcounts; aliasing copies would leak / double-free.
69#[repr(C)]
70pub struct KindedSlot {
71    pub slot: ValueSlot,
72    pub kind: NativeKind,
73}
74
75impl KindedSlot {
76    /// Construct from an already-owned slot + its kind. The caller must
77    /// ensure the slot's bits are a valid representation of `kind` (e.g.
78    /// for heap kinds, one strong-count share owned by this `KindedSlot`).
79    #[inline]
80    pub fn new(slot: ValueSlot, kind: NativeKind) -> Self {
81        Self { slot, kind }
82    }
83
84    /// Convenience: a numeric `Int64`-kind slot.
85    #[inline]
86    pub fn from_int(i: i64) -> Self {
87        Self::new(ValueSlot::from_int(i), NativeKind::Int64)
88    }
89
90    /// Convenience: a `Float64`-kind slot.
91    #[inline]
92    pub fn from_number(n: f64) -> Self {
93        Self::new(ValueSlot::from_number(n), NativeKind::Float64)
94    }
95
96    /// Convenience: a `Float32`-kind slot. ADR-006 §2.7.5 amendment
97    /// (Round 19 S1.5 W12-nativekind-scalar-additions, 2026-05-14).
98    /// `f32` is a 4-byte scalar; slot bits store the IEEE-754
99    /// single-precision pattern zero-extended into the low 32 bits of
100    /// the 8-byte slot (via `f32::to_bits` reinterpreted as `u64`).
101    /// Drop is a no-op (inline scalar, no `Arc<T>` payload).
102    #[inline]
103    pub fn from_f32(f: f32) -> Self {
104        Self::new(
105            ValueSlot::from_raw(f.to_bits() as u64),
106            NativeKind::Float32,
107        )
108    }
109
110    /// Convenience: a `Bool`-kind slot.
111    #[inline]
112    pub fn from_bool(b: bool) -> Self {
113        Self::new(ValueSlot::from_bool(b), NativeKind::Bool)
114    }
115
116    /// Convenience: a `String`-kind slot from an `Arc<String>`.
117    #[inline]
118    pub fn from_string_arc(s: Arc<String>) -> Self {
119        Self::new(ValueSlot::from_string_arc(s), NativeKind::String)
120    }
121
122    /// Convenience: a `Ptr(HeapKind::TypedObject)`-kind slot from an
123    /// `Arc<TypedObjectStorage>`. **Wave 2 Agent D1 (2026-05-14): legacy
124    /// transitional constructor** — see `ValueSlot::from_typed_object`
125    /// docstring for the Arc-vs-raw-pointer staging. Slot bits are
126    /// `Arc::into_raw(o)`.
127    #[inline]
128    pub fn from_typed_object(o: Arc<TypedObjectStorage>) -> Self {
129        Self::new(
130            ValueSlot::from_typed_object(o),
131            NativeKind::Ptr(HeapKind::TypedObject),
132        )
133    }
134
135    /// Convenience: a `Ptr(HeapKind::TypedObject)`-kind slot from a raw
136    /// `*const TypedObjectStorage`. **Wave 2 Agent D1 (2026-05-14): v2-raw
137    /// raw-pointer constructor.** Per ADR-006 §2.3 amendment + audit §4.3
138    /// O-3.a resolution. Pairs with `TypedObjectStorage::_new` allocator;
139    /// refcount discipline goes through the on-header refcount via
140    /// `v2_retain` / `v2_release` (NOT Rust `Arc::increment/decrement_
141    /// strong_count`). See `ValueSlot::from_typed_object_raw` docstring
142    /// for the full call-site migration pattern.
143    #[inline]
144    pub fn from_typed_object_raw(ptr: *const TypedObjectStorage) -> Self {
145        Self::new(
146            ValueSlot::from_typed_object_raw(ptr),
147            NativeKind::Ptr(HeapKind::TypedObject),
148        )
149    }
150
151    // V3-S5 ckpt-4 (2026-05-15): `from_typed_array(a: Arc<TypedArrayData>)`
152    // DELETED in lockstep with the `TypedArrayData` enum + `TypedBuffer<T>` /
153    // `AlignedTypedBuffer` wrapper layer + `ValueSlot::from_typed_array`
154    // constructor. W12-typed-array-data-deletion-audit §3.5 + §B +
155    // ADR-006 §2.7.24 Q25.A SUPERSEDED. Replacement (downstream wave):
156    // per-element-kind convenience constructors —
157    // `from_typed_array_f64(Arc<TypedArray<f64>>)` /
158    // `from_typed_array_i64(...)` / etc. Refusal #1 binding.
159
160    /// Convenience: a `Ptr(HeapKind::HashMap)`-kind slot.
161    ///
162    /// **Wave 2 Round 3b C2-joint ckpt-2 (2026-05-14):** parameter type
163    /// flipped from `Arc<HashMapData>` (non-generic) to
164    /// `Arc<HashMapKindedRef>` (per-V enum carrier in Arc) per ADR-006
165    /// §2.7.24 Q25.B SUPERSEDED.
166    #[inline]
167    pub fn from_hashmap(h: Arc<crate::heap_value::HashMapKindedRef>) -> Self {
168        Self::new(
169            ValueSlot::from_hashmap(h),
170            NativeKind::Ptr(HeapKind::HashMap),
171        )
172    }
173
174    /// Convenience: a `Ptr(HeapKind::HashSet)`-kind slot. Mirror of
175    /// `from_hashmap` per ADR-006 §2.7.15 / Q16 amendment (Wave 13
176    /// W13-hashset-rebuild). Set is a HashMap sibling — full
177    /// `HeapValue::HashSet(Arc<HashSetData>)` arm, not pure-discriminator.
178    #[inline]
179    pub fn from_hashset(h: Arc<HashSetData>) -> Self {
180        Self::new(
181            ValueSlot::from_hashset(h),
182            NativeKind::Ptr(HeapKind::HashSet),
183        )
184    }
185
186    /// Convenience: a `Ptr(HeapKind::Deque)`-kind slot. Mirror of
187    /// `from_hashset` per ADR-006 §2.7.19 / Q20 amendment (Wave 15
188    /// W15-deque). Deque is a HashSet sibling — full
189    /// `HeapValue::Deque(Arc<DequeData>)` arm, not pure-discriminator.
190    #[inline]
191    pub fn from_deque(d: Arc<DequeData>) -> Self {
192        Self::new(
193            ValueSlot::from_deque(d),
194            NativeKind::Ptr(HeapKind::Deque),
195        )
196    }
197
198    /// Convenience: a `Ptr(HeapKind::Channel)`-kind slot. Mirror of
199    /// `from_hashset` per ADR-006 §2.7.20 / Q21 amendment (Wave 15
200    /// W15-channel-rebuild). Channel is the first concurrency
201    /// primitive to land kinded — full
202    /// `HeapValue::Channel(Arc<ChannelData>)` arm, not pure-discriminator.
203    /// Inner state carries `Mutex<ChannelInner>`; cloning the outer
204    /// `Arc` hands out a fresh endpoint of the same channel.
205    #[inline]
206    pub fn from_channel(c: Arc<ChannelData>) -> Self {
207        Self::new(
208            ValueSlot::from_channel(c),
209            NativeKind::Ptr(HeapKind::Channel),
210        )
211    }
212
213    /// Convenience: a `Ptr(HeapKind::TraitObject)`-kind slot. Mirror
214    /// of `from_typed_object` per ADR-006 §2.7.24 / Q25.C amendment
215    /// (Wave 17 W17-trait-object-storage, 2026-05-11). Full
216    /// `HeapValue::TraitObject(Arc<TraitObjectStorage>)` arm —
217    /// `TraitObjectStorage` is the typed-Arc replacement for the
218    /// bulldozer-deleted `HeapValue::TraitObject { value: Box<u64>,
219    /// vtable: Arc<VTable> }` shape.
220    ///
221    /// **Wave 2 Agent E (2026-05-14): legacy transitional constructor.**
222    /// See `ValueSlot::from_trait_object` docstring for the Arc-vs-raw-pointer
223    /// staging.
224    #[inline]
225    pub fn from_trait_object(t: Arc<TraitObjectStorage>) -> Self {
226        Self::new(
227            ValueSlot::from_trait_object(t),
228            NativeKind::Ptr(HeapKind::TraitObject),
229        )
230    }
231
232    /// Convenience: a `Ptr(HeapKind::TraitObject)`-kind slot from a raw
233    /// `*const TraitObjectStorage`. **Wave 2 Agent E (2026-05-14): v2-raw
234    /// raw-pointer constructor.** Per ADR-006 §Q25.C.5 amendment + audit
235    /// §4.3 O-3.a resolution. Pairs with `TraitObjectStorage::_new`
236    /// allocator; refcount discipline goes through the on-header refcount
237    /// via `v2_retain` / `v2_release` (NOT Rust `Arc::increment/decrement_
238    /// strong_count`). See `ValueSlot::from_trait_object_raw` docstring
239    /// for the full call-site migration pattern.
240    #[inline]
241    pub fn from_trait_object_raw(ptr: *const TraitObjectStorage) -> Self {
242        Self::new(
243            ValueSlot::from_trait_object_raw(ptr),
244            NativeKind::Ptr(HeapKind::TraitObject),
245        )
246    }
247
248    /// Convenience: a `Ptr(HeapKind::Mutex)`-kind slot. Mirror of
249    /// `from_channel` per ADR-006 §2.7.25 amendment (Wave 17
250    /// W17-concurrency, 2026-05-11). Full
251    /// `HeapValue::Mutex(Arc<MutexData>)` arm.
252    #[inline]
253    pub fn from_mutex(m: Arc<MutexData>) -> Self {
254        Self::new(
255            ValueSlot::from_mutex(m),
256            NativeKind::Ptr(HeapKind::Mutex),
257        )
258    }
259
260    /// Convenience: a `Ptr(HeapKind::Atomic)`-kind slot. Mirror of
261    /// `from_channel` per ADR-006 §2.7.25 amendment (Wave 17
262    /// W17-concurrency, 2026-05-11). Full
263    /// `HeapValue::Atomic(Arc<AtomicData>)` arm. i64-only at landing.
264    #[inline]
265    pub fn from_atomic(a: Arc<AtomicData>) -> Self {
266        Self::new(
267            ValueSlot::from_atomic(a),
268            NativeKind::Ptr(HeapKind::Atomic),
269        )
270    }
271
272    /// Convenience: a `Ptr(HeapKind::Lazy)`-kind slot. Mirror of
273    /// `from_channel` per ADR-006 §2.7.25 amendment (Wave 17
274    /// W17-concurrency, 2026-05-11). Full
275    /// `HeapValue::Lazy(Arc<LazyData>)` arm.
276    #[inline]
277    pub fn from_lazy(l: Arc<LazyData>) -> Self {
278        Self::new(
279            ValueSlot::from_lazy(l),
280            NativeKind::Ptr(HeapKind::Lazy),
281        )
282    }
283
284    /// Convenience: a `Ptr(HeapKind::Temporal)`-kind slot. ADR-006
285    /// §2.7.6 / Q8 cardinality amendment (Wave 3 W17-from-temporal-
286    /// instant-constructors, 2026-05-12). Slot bits are
287    /// `Arc::into_raw(Arc<TemporalData>) as u64`; recovery goes through
288    /// the canonical 5-arm receiver-recovery pattern (reconstruct via
289    /// `Arc::<TemporalData>::from_raw`, clone, `into_raw` to restore).
290    /// Mirror of `from_iterator` typed-Arc dispatch shape — `TemporalData`
291    /// is the consolidated DateTime / Duration / TimeSpan / Timeframe /
292    /// TimeReference / DateTimeExpr / DataDateTimeRef carrier per
293    /// `heap_value.rs::TemporalData`. The Drop / Clone arms for
294    /// `HeapKind::Temporal` already dispatch the matching strong-count
295    /// retain/release; this constructor pairs with them by the §2.7.6 /
296    /// Q8 bounded carrier-API rule (one constructor per `NativeKind` heap
297    /// variant, no new heap-variant cardinality introduced).
298    #[inline]
299    pub fn from_temporal(arc: Arc<crate::heap_value::TemporalData>) -> Self {
300        let bits = Arc::into_raw(arc) as u64;
301        Self::new(
302            ValueSlot::from_raw(bits),
303            NativeKind::Ptr(HeapKind::Temporal),
304        )
305    }
306
307    /// Convenience: a `Ptr(HeapKind::Instant)`-kind slot. ADR-006
308    /// §2.7.6 / Q8 cardinality amendment (Wave 3 W17-from-temporal-
309    /// instant-constructors, 2026-05-12). Slot bits are
310    /// `Arc::into_raw(Arc<std::time::Instant>) as u64`; recovery goes
311    /// through the canonical 5-arm receiver-recovery pattern. Mirror of
312    /// `from_temporal` for the `Instant` sibling — `Instant` rides
313    /// `Arc<std::time::Instant>` directly (no `InstantData` wrapper).
314    /// The Drop / Clone arms for `HeapKind::Instant` already dispatch
315    /// the matching strong-count retain/release; this constructor pairs
316    /// with them by the §2.7.6 / Q8 bounded carrier-API rule.
317    #[inline]
318    pub fn from_instant(arc: Arc<std::time::Instant>) -> Self {
319        let bits = Arc::into_raw(arc) as u64;
320        Self::new(
321            ValueSlot::from_raw(bits),
322            NativeKind::Ptr(HeapKind::Instant),
323        )
324    }
325
326    /// Convenience: a `Ptr(HeapKind::Iterator)`-kind slot. Stores the
327    /// `Arc::into_raw` pointer directly per ADR-006 §2.7.16 / Q17 (W13-
328    /// iterator-state).
329    #[inline]
330    pub fn from_iterator(it: Arc<IteratorState>) -> Self {
331        let bits = Arc::into_raw(it) as u64;
332        Self::new(
333            ValueSlot::from_raw(bits),
334            NativeKind::Ptr(HeapKind::Iterator),
335        )
336    }
337
338    /// Convenience: a `Ptr(HeapKind::PriorityQueue)`-kind slot. Mirror
339    /// of `from_hashset` per ADR-006 §2.7.18 / Q19 amendment (Wave 15
340    /// W15-priority-queue). PriorityQueue is a HashSet sibling — full
341    /// `HeapValue::PriorityQueue(Arc<PriorityQueueData>)` arm, not
342    /// pure-discriminator.
343    #[inline]
344    pub fn from_priority_queue(p: Arc<PriorityQueueData>) -> Self {
345        Self::new(
346            ValueSlot::from_priority_queue(p),
347            NativeKind::Ptr(HeapKind::PriorityQueue),
348        )
349    }
350
351    /// Convenience: a `Ptr(HeapKind::Range)`-kind slot. Stores the
352    /// `Arc<RangeData>` directly per ADR-006 §2.7.23 / Q24 (W15-range).
353    /// Slot bits are `Arc::into_raw(Arc<RangeData>) as u64`; recovery
354    /// goes through `slot.as_heap_value()` → `HeapValue::Range(arc)`
355    /// per ADR-005 §1 single-discriminator.
356    #[inline]
357    pub fn from_range(r: Arc<RangeData>) -> Self {
358        Self::new(
359            ValueSlot::from_range(r),
360            NativeKind::Ptr(HeapKind::Range),
361        )
362    }
363
364    /// Convenience: a `Ptr(HeapKind::Content)`-kind slot. Stores the
365    /// `Arc<ContentNode>` directly per ADR-006 §2.3 (W18.6 R8 W3
366    /// 2026-05-24 — supervisor D3+D4 Display.display() → content +
367    /// ContentNode user-facing type exposure). Slot bits are
368    /// `Arc::into_raw(Arc<ContentNode>) as u64`; the Drop / Clone arms
369    /// for `HeapKind::Content` already dispatch the matching strong-
370    /// count retain/release. Used by the `Content.text(...)` /
371    /// `Content.code(...)` / etc. user-facing constructor builtins
372    /// (`ContentTextCtor` family) and by user-defined `Display` impls
373    /// whose `method display() -> content` return value is pushed
374    /// through this carrier.
375    #[inline]
376    pub fn from_content(c: Arc<crate::content::ContentNode>) -> Self {
377        Self::new(
378            ValueSlot::from_content(c),
379            NativeKind::Ptr(HeapKind::Content),
380        )
381    }
382
383    /// Convenience: a `Ptr(HeapKind::Result)`-kind slot. ADR-006 §2.7.17 /
384    /// Q18 amendment (Wave 14 W14-variant-codegen). Mirror of
385    /// `from_iterator` typed-Arc dispatch shape.
386    #[inline]
387    pub fn from_result(r: Arc<ResultData>) -> Self {
388        Self::new(
389            ValueSlot::from_result(r),
390            NativeKind::Ptr(HeapKind::Result),
391        )
392    }
393
394    /// Convenience: a `Ptr(HeapKind::Option)`-kind slot. ADR-006 §2.7.17 /
395    /// Q18 amendment (Wave 14 W14-variant-codegen).
396    #[inline]
397    pub fn from_option(o: Arc<OptionData>) -> Self {
398        Self::new(
399            ValueSlot::from_option(o),
400            NativeKind::Ptr(HeapKind::Option),
401        )
402    }
403
404    /// Convenience: a `Ptr(HeapKind::Decimal)`-kind slot.
405    #[inline]
406    pub fn from_decimal(d: Arc<rust_decimal::Decimal>) -> Self {
407        Self::new(
408            ValueSlot::from_decimal(d),
409            NativeKind::Ptr(HeapKind::Decimal),
410        )
411    }
412
413    /// Convenience: a `StringV2`-kind slot from a v2-raw `*const StringObj`
414    /// pointer. ADR-006 §2.7.5 amendment (Wave 2 Agent B W12-StringV2-
415    /// DecimalV2-NativeKind-additions, 2026-05-14): paired with
416    /// `NativeKind::StringV2` per the audit §H.4 H-c decision. Slot bits
417    /// = `ptr as u64`; the `KindedSlot` owns one refcount share on the
418    /// underlying `StringObj` — Drop dispatches the matching `v2_release`
419    /// against the `HeapHeader` at offset 0.
420    ///
421    /// Caller's construction-side contract: `ptr` MUST point to a live
422    /// `StringObj` whose refcount has been incremented (typically via
423    /// `v2_retain` at the producing `op_typed_array_get` site) to claim
424    /// the share this `KindedSlot` now owns. Mirror of `from_string_arc`'s
425    /// "slot owns one strong share" contract — but the underlying retain
426    /// is `v2_retain` against the `repr(C)` HeapHeader, not
427    /// `Arc::increment_strong_count` against an `Arc<String>`.
428    #[inline]
429    pub fn from_string_v2_ptr(ptr: *const crate::v2::string_obj::StringObj) -> Self {
430        Self::new(ValueSlot::from_string_v2_ptr(ptr), NativeKind::StringV2)
431    }
432
433    /// Convenience: a `DecimalV2`-kind slot from a v2-raw `*const DecimalObj`
434    /// pointer. ADR-006 §2.7.5 amendment (Wave 2 Agent B W12-StringV2-
435    /// DecimalV2-NativeKind-additions, 2026-05-14): mirror of
436    /// `from_string_v2_ptr` for the `DecimalObj` sibling. Same construction-
437    /// side contract.
438    #[inline]
439    pub fn from_decimal_v2_ptr(ptr: *const crate::v2::decimal_obj::DecimalObj) -> Self {
440        Self::new(ValueSlot::from_decimal_v2_ptr(ptr), NativeKind::DecimalV2)
441    }
442
443    /// Convenience: a `Ptr(HeapKind::BigInt)`-kind slot.
444    #[inline]
445    pub fn from_bigint(b: Arc<i64>) -> Self {
446        Self::new(ValueSlot::from_bigint(b), NativeKind::Ptr(HeapKind::BigInt))
447    }
448
449    /// Convenience: a `Ptr(HeapKind::IoHandle)`-kind slot from an
450    /// `Arc<IoHandleData>`. R8 W6 G.1 W17-marshal-return-arms close
451    /// (2026-05-24): mirrors the existing 14 typed-Arc constructor
452    /// precedents (ADR-005 §1 single-discriminator + ADR-006 §2.7.6 / Q8
453    /// bounded carrier-API). Slot bits = `Arc::into_raw(h) as u64` via
454    /// `ValueSlot::from_io_handle`; the Drop / Clone arms for
455    /// `HeapKind::IoHandle` (`kinded_slot.rs` ~line 868 / ~line 1227)
456    /// already dispatch the matching `Arc::increment/decrement_strong_
457    /// count::<IoHandleData>` retain/release. Used by
458    /// `project_typed_return` (`vm_impl/modules.rs`) to land the
459    /// `ConcreteReturn::IoHandle(Arc<IoHandleData>)` arm from
460    /// `transport::tcp()` / `io::tcp_listen()` / `file::open()` etc.
461    /// without producer/consumer divergence (pre-fix VM surfaced
462    /// `project_typed_return: W17-marshal-return-arms` while JIT
463    /// returned ec=0 garbage).
464    #[inline]
465    pub fn from_io_handle(h: Arc<IoHandleData>) -> Self {
466        Self::new(
467            ValueSlot::from_io_handle(h),
468            NativeKind::Ptr(HeapKind::IoHandle),
469        )
470    }
471
472    /// Convenience: a `Ptr(HeapKind::DataTable)`-kind slot from an
473    /// `Arc<DataTable>`. R8 W6 G.1 W17-marshal-return-arms close
474    /// (2026-05-24): sibling of `from_io_handle` — same family of
475    /// `ConcreteReturn` discriminant gap (disc 15 vs disc 16). Slot
476    /// bits = `Arc::into_raw(d) as u64` via `ValueSlot::from_data_table`;
477    /// the Drop / Clone arms for `HeapKind::DataTable` (`kinded_slot.rs`
478    /// ~line 863 / ~line 1222) already dispatch the matching
479    /// `Arc::increment/decrement_strong_count::<DataTable>`
480    /// retain/release. Used by `project_typed_return` to land the
481    /// `ConcreteReturn::DataTable(Arc<DataTable>)` arm from
482    /// `arrow_module` / wire-conversion factory returns.
483    #[inline]
484    pub fn from_data_table(d: Arc<crate::datatable::DataTable>) -> Self {
485        Self::new(
486            ValueSlot::from_data_table(d),
487            NativeKind::Ptr(HeapKind::DataTable),
488        )
489    }
490
491    /// Convenience: a `Char`-kind slot. ADR-006 §2.7.5 amendment (Round
492    /// 19 S1.5 W12-nativekind-scalar-additions, 2026-05-14): Char joins
493    /// the scalar bucket — `char` is `Copy + 4-byte` (UTF-32 codepoint),
494    /// no Arc payload. Slot bits store `c as u32` zero-extended into
495    /// the low 32 bits of the 8-byte slot.
496    ///
497    /// Pre-amendment (Round 18 and earlier) this constructor returned
498    /// a slot with kind `NativeKind::Ptr(HeapKind::Char)` — the inline-
499    /// codepoint payload tagged through `HeapKind` for dispatch
500    /// uniformity. The post-amendment shape is a pure scalar variant
501    /// (`NativeKind::Char`), aligning Char with the other 4-byte
502    /// scalars (`Int32` / `UInt32` / `Float32`) per §Q8 carrier-API
503    /// bound (one constructor per scalar variant). The
504    /// `NativeKind::Ptr(HeapKind::Char)` label still exists in source
505    /// (direct `push_kinded(c as u64, NativeKind::Ptr(HeapKind::Char))`
506    /// call-sites have NOT been migrated in this dispatch — a future
507    /// cluster-1 hardening sub-cluster retires that parallel label).
508    /// Drop is a no-op (inline scalar; the `NativeKind::Char` arm in
509    /// `Drop` is part of the inline-scalar group).
510    #[inline]
511    pub fn from_char(c: char) -> Self {
512        Self::new(ValueSlot::from_char(c), NativeKind::Char)
513    }
514
515    /// Convenience: a `Ptr(HeapKind::Matrix)`-kind slot. ADR-006 §2.7.22
516    /// amendment (Round 18 S3 W12-matrix-floatslice-heapkind-exit,
517    /// 2026-05-13). Slot bits are `Arc::into_raw(Arc<MatrixData>) as u64`;
518    /// recovery goes through the canonical reconstruct-clone-restore
519    /// pattern (`Arc::<MatrixData>::from_raw(bits)` → clone → `into_raw`)
520    /// to bump the inner share while preserving the carrier's owned
521    /// outer share. Mirror of `from_iterator` / `from_range` typed-Arc
522    /// dispatch shape — `as_heap_value()` on a Matrix-labeled slot is
523    /// unsound (the slot bits are an `Arc<MatrixData>` pointer, not a
524    /// `*const HeapValue`). The Drop / Clone arms for `HeapKind::Matrix`
525    /// dispatch the matching `Arc::increment/decrement_strong_count
526    /// ::<MatrixData>` retain/release.
527    #[inline]
528    pub fn from_matrix(m: Arc<MatrixData>) -> Self {
529        let bits = Arc::into_raw(m) as u64;
530        Self::new(ValueSlot::from_raw(bits), NativeKind::Ptr(HeapKind::Matrix))
531    }
532
533    /// Convenience: a `Ptr(HeapKind::MatrixSlice)`-kind slot. ADR-006
534    /// §2.7.22 amendment (Round 18 S3 W12-matrix-floatslice-heapkind-exit,
535    /// 2026-05-13). Slot bits are
536    /// `Arc::into_raw(Arc<MatrixSliceData>) as u64`. Same typed-Arc
537    /// pure-discriminator dispatch shape as `from_matrix`. The inner
538    /// `MatrixSliceData { parent, offset, len }` retains a separate
539    /// strong-count share on its parent matrix; cloning the outer share
540    /// does NOT bump the parent — that bump happens at
541    /// `MatrixSliceData::clone` (auto-derived) when the inner struct is
542    /// duplicated under `Arc::make_mut`.
543    #[inline]
544    pub fn from_matrix_slice(s: Arc<MatrixSliceData>) -> Self {
545        let bits = Arc::into_raw(s) as u64;
546        Self::new(
547            ValueSlot::from_raw(bits),
548            NativeKind::Ptr(HeapKind::MatrixSlice),
549        )
550    }
551
552    /// Convenience: a `Ptr(HeapKind::ModuleFn)`-kind slot. Stores the
553    /// `module_fn_id` as raw `u64` slot bits directly (inline-scalar
554    /// payload — no `Arc<T>`, no heap state). Same shape as
555    /// `from_char` / `from_future` per ADR-006 §2.7.26
556    /// (W17-comptime-vm-dispatch).
557    ///
558    /// Construction-side contract: `id` must index a registered entry
559    /// in `VirtualMachine.module_fn_table`. The dispatch shell at
560    /// `executor/call_convention.rs::call_value_immediate_nb` consumes
561    /// the kind label to route the slot's bits to
562    /// `invoke_module_fn_id_stub` at `CallValue` time.
563    #[inline]
564    pub fn from_module_fn_id(id: u64) -> Self {
565        Self::new(
566            ValueSlot::from_raw(id),
567            NativeKind::Ptr(HeapKind::ModuleFn),
568        )
569    }
570
571    /// Convenience: a `String`-kind slot from a `&str`. Allocates a fresh
572    /// `Arc<String>`. Use `from_string_arc` when you already have the
573    /// `Arc<String>` in hand and want to avoid a clone.
574    #[inline]
575    pub fn from_string(s: &str) -> Self {
576        Self::from_string_arc(Arc::new(s.to_string()))
577    }
578
579    /// A null/none-value `KindedSlot`.
580    ///
581    /// R5b-2-bool-null-sentinel-cluster (ADR-006 §2.7 + §2.7.5 +
582    /// §2.7.7/Q9, 2026-05-19): pre-disposition this returned
583    /// `(ValueSlot::none(), NativeKind::Bool)` as the §2.7 sentinel,
584    /// which collided with legitimate `false` bool slots (both encoded
585    /// as bits=0). The collision caused VM-only divergence per
586    /// W14.2-G6 SURFACE-G6-BOOL-NULL + SURFACE-G6-LET-ONLY-BODY +
587    /// SURFACE-G6-NONE-OUTPUT-ADAPTER. Post-disposition: kind IS the
588    /// discriminator per §2.7.7/Q9 — return `NativeKind::Null`. Drop
589    /// remains a no-op (Null is a non-parametric absence-of-value
590    /// sentinel with no Arc<T> payload).
591    #[inline]
592    pub fn none() -> Self {
593        Self::new(ValueSlot::none(), NativeKind::Null)
594    }
595
596    /// Read the inner slot.
597    #[inline]
598    pub fn slot(&self) -> ValueSlot {
599        self.slot
600    }
601
602    /// Read the kind.
603    #[inline]
604    pub fn kind(&self) -> NativeKind {
605        self.kind
606    }
607
608    /// Raw slot bits. Provided for sites that need to peek at the storage
609    /// shape (e.g. wire serialization). Prefer typed accessors.
610    #[inline]
611    pub fn raw(&self) -> u64 {
612        self.slot.raw()
613    }
614
615    // ── Scalar accessors (ADR-006 §2.7.6 / Q8) ────────────────────────────
616    //
617    // One accessor per `NativeKind` *scalar* variant. Each kind-dispatches
618    // on `self.kind` and returns `Some(payload)` only when the kind matches
619    // exactly. Heap variants do NOT get per-variant accessors here; bodies
620    // dispatching on a heap-typed `KindedSlot` use
621    // `kinded_slot.slot.as_heap_value() -> &HeapValue` and pattern-match,
622    // preserving ADR-005 §1's single-discriminator discipline.
623
624    /// Read as `i64` if `self.kind == NativeKind::Int64`, else `None`.
625    #[inline]
626    pub fn as_i64(&self) -> Option<i64> {
627        match self.kind {
628            NativeKind::Int64 => Some(self.slot.as_i64()),
629            _ => None,
630        }
631    }
632
633    /// Read as `f64` if `self.kind == NativeKind::Float64`, else `None`.
634    #[inline]
635    pub fn as_f64(&self) -> Option<f64> {
636        match self.kind {
637            NativeKind::Float64 => Some(self.slot.as_f64()),
638            _ => None,
639        }
640    }
641
642    /// Read as `bool` if `self.kind == NativeKind::Bool`, else `None`.
643    #[inline]
644    pub fn as_bool(&self) -> Option<bool> {
645        match self.kind {
646            NativeKind::Bool => Some(self.slot.as_bool()),
647            _ => None,
648        }
649    }
650
651    /// Read as `char` if `self.kind == NativeKind::Char`, else `None`.
652    /// ADR-006 §2.7.5 amendment (Round 19 S1.5, 2026-05-14): the §Q8
653    /// carrier-API bound binds `as_char` to the new scalar
654    /// `NativeKind::Char` variant. The pre-amendment
655    /// `NativeKind::Ptr(HeapKind::Char)` carrier label is ALSO recognized
656    /// for cross-tier-compatibility — the label still exists in source
657    /// (direct `push_kinded(c as u64, NativeKind::Ptr(HeapKind::Char))`
658    /// call-sites have NOT been migrated in this dispatch); recognizing
659    /// both labels avoids producer/consumer mismatch when those call-
660    /// sites flow values through code paths that materialize as
661    /// `KindedSlot` before consuming `as_char`. Both labels store
662    /// codepoint bits zero-extended in the low 32 bits of the slot, so
663    /// the read is identical in either kind.
664    #[inline]
665    pub fn as_char(&self) -> Option<char> {
666        match self.kind {
667            NativeKind::Char | NativeKind::Ptr(HeapKind::Char) => self.slot.as_char(),
668            _ => None,
669        }
670    }
671
672    /// Read as `f32` if `self.kind == NativeKind::Float32`, else `None`.
673    /// ADR-006 §2.7.5 amendment (Round 19 S1.5, 2026-05-14). Slot bits
674    /// store the IEEE-754 single-precision pattern zero-extended into
675    /// the low 32 bits; `f32::from_bits` reinterprets the low 32 bits.
676    #[inline]
677    pub fn as_f32(&self) -> Option<f32> {
678        match self.kind {
679            NativeKind::Float32 => Some(f32::from_bits(self.slot.raw() as u32)),
680            _ => None,
681        }
682    }
683
684    /// Read as `&str` if `self.kind == NativeKind::String` (legacy Arc<String>
685    /// carrier) or `NativeKind::StringV2` (v2-raw `*const StringObj` carrier),
686    /// else `None`. Both carriers expose the same UTF-8 bytes; the accessor
687    /// dispatches on kind and borrows the inner `&str` for the lifetime of
688    /// `&self`. The carrier owns one strong-count share (Arc<String>) /
689    /// HeapHeader refcount (StringObj), so the inner string is alive while
690    /// `&self` lives.
691    ///
692    /// D-β string-join receiver-kind fix (v0.3 KC #6(d), 2026-05-22):
693    /// the pre-fix arm gated only on `NativeKind::String`. Elements read
694    /// from a v2-raw `TypedArray<*const StringObj>` (i.e. an `Array<string>`
695    /// literal lowered through `NewTypedArrayString` + `TypedArrayPushString`)
696    /// flow through `TypedArrayGetString` (`v2_handlers/array.rs:702`) which
697    /// pushes `NativeKind::StringV2`; without the StringV2 arm here, every
698    /// universal-method dispatch on a v2-raw string receiver (e.g.
699    /// `arr[i].toString()` inside `Vec<T>.join`'s body) surfaced
700    /// "TypeError: expected string receiver, got non-string kind". Per
701    /// ADR-006 §2.7.5 amendment Wave 2 Agent B both carrier labels store
702    /// equivalent UTF-8 bytes; the per-carrier read is the producer-site
703    /// proof, not fabrication.
704    #[inline]
705    pub fn as_str(&self) -> Option<&str> {
706        match self.kind {
707            NativeKind::String => {
708                let bits = self.slot.raw();
709                if bits == 0 {
710                    return None;
711                }
712                // SAFETY: per the construction-side contract, `NativeKind::String`
713                // means the slot bits are `Arc::into_raw::<String>` and this
714                // `KindedSlot` owns one strong-count share (so the inner
715                // `String` is alive). The returned `&str` borrows from
716                // `&self`; lifetime is bounded by the slot's ownership.
717                let s: &String = unsafe { &*(bits as *const String) };
718                Some(s.as_str())
719            }
720            NativeKind::StringV2 => {
721                let bits = self.slot.raw();
722                if bits == 0 {
723                    return None;
724                }
725                // SAFETY: per ADR-006 §2.7.5 amendment Wave 2 Agent B, when
726                // `kind == NativeKind::StringV2` the slot bits are
727                // `ptr as u64` where `ptr: *const StringObj` (the v2-raw
728                // `HeapHeader`-prefixed UTF-8 carrier per
729                // `crates/shape-value/src/v2/string_obj.rs`). The carrier
730                // owns one HeapHeader refcount share for the duration of
731                // `&self`; `StringObj::as_str(ptr)` borrows the inner UTF-8
732                // bytes — lifetime is bounded by the slot's ownership.
733                let ptr = bits as *const crate::v2::string_obj::StringObj;
734                Some(unsafe {
735                    crate::v2::string_obj::StringObj::as_str(ptr)
736                })
737            }
738            _ => None,
739        }
740    }
741}
742
743impl std::fmt::Debug for KindedSlot {
744    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
745        f.debug_struct("KindedSlot")
746            .field("slot", &self.slot)
747            .field("kind", &self.kind)
748            .finish()
749    }
750}
751
752impl Default for KindedSlot {
753    fn default() -> Self {
754        Self::none()
755    }
756}
757
758/// Drop dispatches on `kind` to retire the matching `Arc<T>` strong-count
759/// share. Mirrors `TypedObjectStorage::Drop` in `heap_value.rs:761`.
760impl Drop for KindedSlot {
761    fn drop(&mut self) {
762        let bits = self.slot.raw();
763        if bits == 0 {
764            return;
765        }
766        // SAFETY: per the construction-side contract on every `KindedSlot`
767        // constructor, when `kind` selects a heap arm the slot bits are
768        // the result of `Arc::into_raw::<T>` for the matching `T`. Drop
769        // retires exactly one strong-count share.
770        unsafe {
771            match self.kind {
772                NativeKind::String => {
773                    Arc::decrement_strong_count(bits as *const String);
774                }
775                // Wave 2 Agent B (ADR-006 §2.7.5 amendment, 2026-05-14):
776                // StringV2 / DecimalV2 are v2-raw heap-pointer carriers per
777                // the §H.4 H-c decision. Slot bits are `ptr as u64` where
778                // `ptr: *const StringObj` / `*const DecimalObj`. Refcount
779                // discipline goes through `v2_release` against the
780                // `HeapHeader` at offset 0 of the carrier (NOT
781                // `Arc::decrement_strong_count` — these are manually-
782                // allocated `repr(C)` carriers per `v2/string_obj.rs` /
783                // `v2/decimal_obj.rs`, not `Arc<T>` allocations). On
784                // refcount=0, the carrier's `HeapElement::release_elem`
785                // implementation deallocates the struct.
786                NativeKind::StringV2 => {
787                    use crate::v2::heap_element::HeapElement;
788                    crate::v2::string_obj::StringObj::release_elem(
789                        bits as *const crate::v2::string_obj::StringObj,
790                    );
791                }
792                NativeKind::DecimalV2 => {
793                    use crate::v2::heap_element::HeapElement;
794                    crate::v2::decimal_obj::DecimalObj::release_elem(
795                        bits as *const crate::v2::decimal_obj::DecimalObj,
796                    );
797                }
798                NativeKind::Ptr(hk) => match hk {
799                    HeapKind::String => {
800                        Arc::decrement_strong_count(bits as *const String);
801                    }
802                    // r5c-2-β-δ-(α) (2026-05-20): `HeapKind::TypedArray`
803                    // dispatch arm RE-INSTATED — the V3-S5 ckpt-5-prime
804                    // "no live slot bits carry this kind" claim was
805                    // empirically false (`Array<T>` struct fields + closure
806                    // captures carry it). The carrier is the v2-raw
807                    // `*mut TypedArray<T>` flat struct; release retires one
808                    // refcount share and, on the last share, frees via the
809                    // stamped-element-type `drop_array` / `drop_array_heap`.
810                    // Mirror of the `TypedObject` release arm below
811                    // (4-table lockstep, ADR-006 §2.3 / §2.7.7).
812                    HeapKind::TypedArray => {
813                        crate::v2::typed_array::release_v2_typed_array(bits as *mut u8);
814                    }
815                    // Wave 2 Agent D4 ckpt-2 (ADR-006 §2.3 / §2.7.5
816                    // amendment, 2026-05-14): TypedObject release via
817                    // `HeapElement::release_elem` + carrier-side `_drop`
818                    // (per Agent D1's `impl HeapElement for
819                    // TypedObjectStorage` — calls `v2_release` against the
820                    // HeapHeader at offset 0; on refcount=0 the
821                    // carrier-side `_drop` runs the per-field heap-mask
822                    // walk and deallocates the `repr(C)` struct). Mirror
823                    // of the §2.7.5 StringV2 / DecimalV2 release arms
824                    // above.
825                    HeapKind::TypedObject => {
826                        use crate::v2::heap_element::HeapElement;
827                        TypedObjectStorage::release_elem(
828                            bits as *const TypedObjectStorage,
829                        );
830                    }
831                    HeapKind::HashMap => {
832                        // Wave 2 Round 3b C2-joint ckpt-2 (2026-05-14):
833                        // bits are `Arc::into_raw(Arc<HashMapKindedRef>)`;
834                        // release dispatches outer Arc decrement → enum
835                        // Drop chains to per-V `Arc<HashMapData<V>>` release.
836                        Arc::decrement_strong_count(
837                            bits as *const crate::heap_value::HashMapKindedRef,
838                        );
839                    }
840                    // Wave 13 W13-hashset-rebuild (ADR-006 §2.7.15 / Q16,
841                    // 2026-05-10): mirror of the HashMap arm. Retires
842                    // one `Arc<HashSetData>` strong-count share.
843                    HeapKind::HashSet => {
844                        Arc::decrement_strong_count(bits as *const HashSetData);
845                    }
846                    // Wave 15 W15-deque (ADR-006 §2.7.19 / Q20,
847                    // 2026-05-10): mirror of the HashSet arm. Retires
848                    // one `Arc<DequeData>` strong-count share.
849                    HeapKind::Deque => {
850                        Arc::decrement_strong_count(bits as *const DequeData);
851                    }
852                    // Wave 15 W15-channel-rebuild (ADR-006 §2.7.20 / Q21,
853                    // 2026-05-10): mirror of the HashSet arm. Slot bits
854                    // are `Arc::into_raw(Arc<ChannelData>) as u64`.
855                    // Retires one `Arc<ChannelData>` strong-count share
856                    // — at refcount=0 the inner `ChannelData` Drop runs
857                    // (default-derived) which retires the queued
858                    // `KindedSlot` payloads via their own Drop.
859                    HeapKind::Channel => {
860                        Arc::decrement_strong_count(bits as *const ChannelData);
861                    }
862                    // W17-trait-object-storage (ADR-006 §2.7.24 / Q25.C,
863                    // 2026-05-11): TraitObject mirrors the typed-Arc
864                    // dispatch shape. Slot bits are
865                    // `Arc::into_raw(Arc<TraitObjectStorage>) as u64`.
866                    // Retires one strong-count share — at refcount=0
867                    // the inner `TraitObjectStorage::Drop` runs,
868                    // releasing its inner `Arc<TypedObjectStorage>`
869                    // value half + `Arc<VTable>` vtable half via
870                    // auto-derived `Drop`.
871                    // Wave 2 Agent D4 ckpt-2 (ADR-006 §2.7.24 / Q25.C.5 +
872                    // E close 2026-05-14): TraitObject release via
873                    // `HeapElement::release_elem` + carrier-side `_drop`
874                    // (per Agent E's `impl HeapElement for
875                    // TraitObjectStorage`). Mirror of the TypedObject arm
876                    // above.
877                    HeapKind::TraitObject => {
878                        use crate::v2::heap_element::HeapElement;
879                        TraitObjectStorage::release_elem(
880                            bits as *const TraitObjectStorage,
881                        );
882                    }
883                    // W17-concurrency (ADR-006 §2.7.25, 2026-05-11):
884                    // Mutex / Atomic / Lazy mirror the Channel arm.
885                    // Slot bits are `Arc::into_raw(Arc<MutexData>) /
886                    // Arc<AtomicData> / Arc<LazyData>) as u64`. Retires
887                    // one strong-count share — at refcount=0 the inner
888                    // Drop runs and (for Mutex/Lazy) retires the
889                    // protected `KindedSlot` payload via its own Drop.
890                    HeapKind::Mutex => {
891                        Arc::decrement_strong_count(bits as *const MutexData);
892                    }
893                    HeapKind::Atomic => {
894                        Arc::decrement_strong_count(bits as *const AtomicData);
895                    }
896                    HeapKind::Lazy => {
897                        Arc::decrement_strong_count(bits as *const LazyData);
898                    }
899                    HeapKind::Decimal => {
900                        Arc::decrement_strong_count(bits as *const rust_decimal::Decimal);
901                    }
902                    HeapKind::BigInt => {
903                        Arc::decrement_strong_count(bits as *const i64);
904                    }
905                    HeapKind::DataTable => {
906                        Arc::decrement_strong_count(
907                            bits as *const crate::datatable::DataTable,
908                        );
909                    }
910                    HeapKind::IoHandle => {
911                        Arc::decrement_strong_count(bits as *const IoHandleData);
912                    }
913                    HeapKind::NativeView => {
914                        Arc::decrement_strong_count(bits as *const NativeViewData);
915                    }
916                    HeapKind::Content => {
917                        Arc::decrement_strong_count(
918                            bits as *const crate::content::ContentNode,
919                        );
920                    }
921                    HeapKind::Instant => {
922                        Arc::decrement_strong_count(bits as *const std::time::Instant);
923                    }
924                    HeapKind::Temporal => {
925                        Arc::decrement_strong_count(bits as *const TemporalData);
926                    }
927                    HeapKind::TableView => {
928                        Arc::decrement_strong_count(bits as *const TableViewData);
929                    }
930                    HeapKind::TaskGroup => {
931                        Arc::decrement_strong_count(bits as *const TaskGroupData);
932                    }
933                    // Wave-γ G-heap-filter-expr (ADR-006 §2.3 / §2.7.6 / Q8
934                    // amendment): FilterExpr-kinded `KindedSlot`s own one
935                    // `Arc::into_raw(Arc<FilterNode>)` strong-count share.
936                    // The pre-amendment `HeapKind::NativeView` mislabel
937                    // would have dispatched the share as
938                    // `Arc<NativeViewData>` — wrong-type retire.
939                    HeapKind::FilterExpr => {
940                        Arc::decrement_strong_count(bits as *const FilterNode);
941                    }
942                    // Wave 8 W8-T26 (ADR-006 §2.7.13 / Q14, 2026-05-10):
943                    // mirror of `vm_impl/stack.rs:drop_with_kind` Reference
944                    // arm. Slot bits are `Arc::into_raw(Arc<RefTarget>)`
945                    // directly per §2.7.13's pure-discriminator-style
946                    // dispatch (NOT a `Box<HeapValue>` wrap); retire one
947                    // `Arc<RefTarget>` strong-count share. At refcount=0
948                    // the inner `RefTarget` Drop releases its `receiver`
949                    // typed-Arc share for `TypedField` / `TypedIndex`
950                    // variants — `Local` / `ModuleBinding` variants hold
951                    // no Arc.
952                    HeapKind::Reference => {
953                        Arc::decrement_strong_count(bits as *const RefTarget);
954                    }
955                    // W13-iterator-state (ADR-006 §2.7.16 / Q17,
956                    // 2026-05-10): mirror of `vm_impl/stack.rs::
957                    // drop_with_kind` Iterator arm. Slot bits are
958                    // `Arc::into_raw(Arc<IteratorState>)` directly
959                    // (mirror of FilterExpr / Reference's typed-Arc
960                    // dispatch — NOT a `Box<HeapValue>` wrap); retire
961                    // one `Arc<IteratorState>` strong-count share.
962                    HeapKind::Iterator => {
963                        Arc::decrement_strong_count(bits as *const IteratorState);
964                    }
965                    // Wave 15 W15-priority-queue (ADR-006 §2.7.18 / Q19,
966                    // 2026-05-10): mirror of the HashSet arm. Retires
967                    // one `Arc<PriorityQueueData>` strong-count share —
968                    // PriorityQueue is a HashSet sibling per §2.7.18,
969                    // full-`HeapValue` arm.
970                    HeapKind::PriorityQueue => {
971                        Arc::decrement_strong_count(bits as *const PriorityQueueData);
972                    }
973                    // W15-range (ADR-006 §2.7.23 / Q24, 2026-05-10):
974                    // mirror of `vm_impl/stack.rs::drop_with_kind`
975                    // Range arm. Slot bits are
976                    // `Arc::into_raw(Arc<RangeData>)` directly (typed-Arc
977                    // shape, mirror of HashMap / HashSet / Iterator);
978                    // retire one `Arc<RangeData>` strong-count share.
979                    // RangeData is `Copy`-shaped (four scalar fields,
980                    // no inner Arcs) so refcount=0 just deallocates the
981                    // small heap block.
982                    HeapKind::Range => {
983                        Arc::decrement_strong_count(bits as *const RangeData);
984                    }
985                    // Wave 14 W14-variant-codegen (ADR-006 §2.7.17 / Q18,
986                    // 2026-05-10): mirror of the Iterator arm. Slot
987                    // bits are `Arc::into_raw(Arc<ResultData>)`; retire
988                    // one `Arc<ResultData>` strong-count share. At
989                    // refcount=0 `ResultData::Drop` (auto-derived from
990                    // its embedded `KindedSlot` payload) retires the
991                    // inner-value share recursively.
992                    HeapKind::Result => {
993                        Arc::decrement_strong_count(bits as *const ResultData);
994                    }
995                    HeapKind::Option => {
996                        Arc::decrement_strong_count(bits as *const OptionData);
997                    }
998                    // Char: inline-scalar payload (codepoint bits, not an
999                    // `Arc<T>`). Drop is a no-op; non-zero bits are valid
1000                    // (e.g. `from_char('a')` stores 97).
1001                    HeapKind::Char => {
1002                        // No-op: inline-scalar payload.
1003                    }
1004                    // Round 2.5b W7-closure-retain-parallel (ADR-006
1005                    // §2.7.11 / Q12, 2026-05-09 — lockstep with vm-tier
1006                    // Round 2.5 close `5fa4b19`): a
1007                    // `NativeKind::Ptr(HeapKind::Closure)` slot carries
1008                    // `Arc::into_raw(Arc<HeapValue>) as u64` pointing to
1009                    // a `HeapValue::ClosureRaw(OwnedClosureBlock)` arm.
1010                    // The share carrier at the slot tier is the outer
1011                    // `Arc<HeapValue>`, not the inner `OwnedClosureBlock`'s
1012                    // typed-closure-header refcount (which
1013                    // `OwnedClosureBlock` manages internally on its own
1014                    // `clone()` / `drop()`). Round 2 close (`06cdfce`)
1015                    // committed to this slot-bits shape via
1016                    // `callee.slot.as_heap_value()` →
1017                    // `HeapValue::ClosureRaw(block)` in
1018                    // `call_value_immediate_nb`. The §2.7.11 dispatch
1019                    // shell pops closure-bearing `KindedSlot` carriers
1020                    // whose `Drop` arrives here on every consumed call
1021                    // arg and on the callee itself. Same dispatch
1022                    // shape as the `HeapKind::FilterExpr` §2.7.9
1023                    // amendment (one variant, one matching `Arc<T>`
1024                    // retain/release at the slot tier).
1025                    HeapKind::Closure => {
1026                        Arc::decrement_strong_count(bits as *const HeapValue);
1027                    }
1028                    // `Ptr(HeapKind::Future)` carries the future-id u64
1029                    // directly in `bits` (inline scalar — no heap state,
1030                    // no `Arc<T>` payload). See `async_ops/mod.rs`
1031                    // §"Wave 6.5 / E-async migration" docstring and
1032                    // `printing.rs` `HeapKind::Future` arm. Same shape
1033                    // as `HeapKind::Char`.
1034                    HeapKind::Future => {
1035                        // No-op: future-id inline scalar.
1036                    }
1037                    // W17-comptime-vm-dispatch (ADR-006 §2.7.26, 2026-05-12):
1038                    // `Ptr(HeapKind::ModuleFn)` carries the module-fn-id
1039                    // u64 directly in `bits` (inline scalar — no heap
1040                    // state, no `Arc<T>` payload). Same shape as
1041                    // `HeapKind::Future` / `HeapKind::Char`.
1042                    HeapKind::ModuleFn => {
1043                        // No-op: module-fn-id inline scalar.
1044                    }
1045                    // Wave 8 W8-T25 (ADR-006 §2.7.12 / Q13 amendment,
1046                    // 2026-05-10): `SharedCell`-kinded `KindedSlot`s
1047                    // own one `Arc::into_raw(Arc<SharedCell>)` strong-
1048                    // count share — the runtime-tier carrier shape for
1049                    // an `Arc<SharedCell>` cell-pointer that flows
1050                    // through dispatch-slice / module-binding /
1051                    // exception-payload carriers. Retires one
1052                    // `Arc<SharedCell>` strong-count share. Same dispatch
1053                    // shape as the `HeapKind::FilterExpr` §2.7.9
1054                    // amendment.
1055                    HeapKind::SharedCell => {
1056                        Arc::decrement_strong_count(
1057                            bits as *const crate::v2::closure_layout::SharedCell,
1058                        );
1059                    }
1060                    // ADR-006 §2.7.22 amendment (Round 18 S3, 2026-05-13):
1061                    // Matrix / MatrixSlice slots own one typed-Arc
1062                    // strong-count share. Slot bits are
1063                    // `Arc::into_raw(Arc<MatrixData>) as u64` /
1064                    // `Arc::into_raw(Arc<MatrixSliceData>) as u64`. Retire
1065                    // one matching strong-count share. Typed-Arc
1066                    // pure-discriminator dispatch (mirror of §2.7.9
1067                    // FilterExpr); `as_heap_value()` is unsound on
1068                    // Matrix/MatrixSlice-labeled bits.
1069                    HeapKind::Matrix => {
1070                        Arc::decrement_strong_count(bits as *const MatrixData);
1071                    }
1072                    HeapKind::MatrixSlice => {
1073                        Arc::decrement_strong_count(bits as *const MatrixSliceData);
1074                    }
1075                    // `HeapKind::NativeScalar` has no kinded `Arc<T>`
1076                    // carrier yet — the redesign is the phase-2c
1077                    // surface tracked in ADR-006 §2.7.4. The
1078                    // `v2_stack_tests.rs` round-trip tests for
1079                    // NativeScalar are `todo!()` for the same reason.
1080                    // When the kinded NativeScalar carrier lands, this
1081                    // arm wires its retain/release per the chosen
1082                    // share carrier (per the playbook's
1083                    // surface-and-stop discipline — no Bool-default
1084                    // fallback, no construction-side fabrication).
1085                    // Until then, a non-zero pointer with this kind is
1086                    // a construction-side bug.
1087                    HeapKind::NativeScalar => {
1088                        debug_assert!(
1089                            false,
1090                            "KindedSlot::drop: NativeScalar kinded carrier pending \
1091                             phase-2c kinded redesign (ADR-006 §2.7.4)"
1092                        );
1093                    }
1094                },
1095                // Inline-scalar kinds: nothing to decrement. Bits are raw
1096                // value, not a pointer.
1097                NativeKind::Float64
1098                | NativeKind::NullableFloat64
1099                | NativeKind::Int8
1100                | NativeKind::NullableInt8
1101                | NativeKind::UInt8
1102                | NativeKind::NullableUInt8
1103                | NativeKind::Int16
1104                | NativeKind::NullableInt16
1105                | NativeKind::UInt16
1106                | NativeKind::NullableUInt16
1107                | NativeKind::Int32
1108                | NativeKind::NullableInt32
1109                | NativeKind::UInt32
1110                | NativeKind::NullableUInt32
1111                | NativeKind::Int64
1112                | NativeKind::NullableInt64
1113                | NativeKind::UInt64
1114                | NativeKind::NullableUInt64
1115                | NativeKind::IntSize
1116                | NativeKind::NullableIntSize
1117                | NativeKind::UIntSize
1118                | NativeKind::NullableUIntSize
1119                | NativeKind::Bool
1120                // Round 19 S1.5 W12-nativekind-scalar-additions
1121                // (2026-05-14): Float32 + Char are inline 4-byte scalars
1122                // per ADR-006 §2.7.5 amendment. No `Arc<T>` payload, no
1123                // refcount work. Slot bits are the raw f32 bit pattern
1124                // / `c as u32` zero-extended into the low 32 bits.
1125                | NativeKind::Float32
1126                | NativeKind::Char
1127                // R5b-2-bool-null-sentinel-cluster (ADR-006 §2.7 +
1128                // §2.7.5 + §2.7.7/Q9, 2026-05-19): `NativeKind::Null`
1129                // is a non-parametric absence-of-value sentinel — no
1130                // Arc<T> payload, no refcount work.
1131                | NativeKind::Null => {}
1132            }
1133        }
1134    }
1135}
1136
1137/// Clone dispatches on `kind` to bump the matching `Arc<T>` strong-count.
1138impl Clone for KindedSlot {
1139    fn clone(&self) -> Self {
1140        let bits = self.slot.raw();
1141        if bits == 0 {
1142            return Self {
1143                slot: self.slot,
1144                kind: self.kind,
1145            };
1146        }
1147        // SAFETY: same construction-side contract as Drop. We bump exactly
1148        // one strong-count share and let Rust copy the slot bits.
1149        unsafe {
1150            match self.kind {
1151                NativeKind::String => {
1152                    Arc::increment_strong_count(bits as *const String);
1153                }
1154                // Wave 2 Agent B (ADR-006 §2.7.5 amendment, 2026-05-14):
1155                // StringV2 / DecimalV2 retain via `v2_retain` against the
1156                // HeapHeader at offset 0 of the carrier — mirror of the
1157                // Drop arms above.
1158                NativeKind::StringV2 => {
1159                    let hdr =
1160                        &(*(bits as *const crate::v2::string_obj::StringObj)).header;
1161                    crate::v2::refcount::v2_retain(hdr);
1162                }
1163                NativeKind::DecimalV2 => {
1164                    let hdr =
1165                        &(*(bits as *const crate::v2::decimal_obj::DecimalObj)).header;
1166                    crate::v2::refcount::v2_retain(hdr);
1167                }
1168                NativeKind::Ptr(hk) => match hk {
1169                    HeapKind::String => {
1170                        Arc::increment_strong_count(bits as *const String);
1171                    }
1172                    // r5c-2-β-δ-(α) (2026-05-20): `HeapKind::TypedArray`
1173                    // dispatch arm RE-INSTATED — mirror of the
1174                    // `drop_with_kind` arm above. Retain bumps the v2-raw
1175                    // `TypedArray<T>` on-header refcount via `v2_retain`
1176                    // (element type irrelevant for a retain). Mirror of the
1177                    // `TypedObject` retain arm below (4-table lockstep,
1178                    // ADR-006 §2.3 / §2.7.7).
1179                    HeapKind::TypedArray => {
1180                        crate::v2::typed_array::retain_v2_typed_array(bits as *mut u8);
1181                    }
1182                    // Wave 2 Agent D4 ckpt-2 (ADR-006 §2.3 / §2.7.5
1183                    // amendment, 2026-05-14): TypedObject retain via
1184                    // `v2_retain` against the HeapHeader at offset 0 of
1185                    // the v2-raw carrier. Mirror of the §2.7.5 StringV2
1186                    // / DecimalV2 retain arms above (Agent B precedent).
1187                    HeapKind::TypedObject => {
1188                        let hdr =
1189                            &(*(bits as *const TypedObjectStorage)).header;
1190                        crate::v2::refcount::v2_retain(hdr);
1191                    }
1192                    HeapKind::HashMap => {
1193                        // Wave 2 Round 3b C2-joint ckpt-2 (2026-05-14):
1194                        // bits are `Arc::into_raw(Arc<HashMapKindedRef>)`;
1195                        // retain dispatches outer Arc increment (the per-V
1196                        // inner `Arc<HashMapData<V>>` is preserved by-share
1197                        // via the enum's structural sharing).
1198                        Arc::increment_strong_count(
1199                            bits as *const crate::heap_value::HashMapKindedRef,
1200                        );
1201                    }
1202                    // Wave 13 W13-hashset-rebuild (ADR-006 §2.7.15 / Q16,
1203                    // 2026-05-10): mirror of the HashMap arm. Bumps one
1204                    // `Arc<HashSetData>` strong-count share.
1205                    HeapKind::HashSet => {
1206                        Arc::increment_strong_count(bits as *const HashSetData);
1207                    }
1208                    // Wave 15 W15-deque (ADR-006 §2.7.19 / Q20,
1209                    // 2026-05-10): mirror of the HashSet arm. Bumps
1210                    // one `Arc<DequeData>` strong-count share.
1211                    HeapKind::Deque => {
1212                        Arc::increment_strong_count(bits as *const DequeData);
1213                    }
1214                    // Wave 15 W15-channel-rebuild (ADR-006 §2.7.20 / Q21,
1215                    // 2026-05-10): mirror of the HashSet arm above. Bumps
1216                    // one `Arc<ChannelData>` strong-count share — the
1217                    // outer Arc clone hands out a fresh endpoint of the
1218                    // same channel (interior `Mutex<ChannelInner>` is
1219                    // shared, NOT cloned).
1220                    HeapKind::Channel => {
1221                        Arc::increment_strong_count(bits as *const ChannelData);
1222                    }
1223                    // W17-trait-object-storage (ADR-006 §2.7.24 / Q25.C,
1224                    // 2026-05-11): TraitObject mirrors the typed-Arc
1225                    // dispatch shape. Bumps one strong-count share on
1226                    // the outer `Arc<TraitObjectStorage>` — inner
1227                    // `Arc<TypedObjectStorage>` value half and
1228                    // `Arc<VTable>` vtable half stay shared with the
1229                    // source carrier. `Arc::ptr_eq` on the vtable
1230                    // preserves the §Q25.C.2 `Self`-arg identity
1231                    // contract across the clone.
1232                    // Wave 2 Agent D4 ckpt-2 (ADR-006 §2.7.24 / Q25.C.5 +
1233                    // E close 2026-05-14): TraitObject retain via
1234                    // `v2_retain` against the HeapHeader at offset 0 of
1235                    // the v2-raw carrier. Mirror of the TypedObject arm
1236                    // above.
1237                    HeapKind::TraitObject => {
1238                        let hdr =
1239                            &(*(bits as *const TraitObjectStorage)).header;
1240                        crate::v2::refcount::v2_retain(hdr);
1241                    }
1242                    // W17-concurrency (ADR-006 §2.7.25, 2026-05-11):
1243                    // Mutex / Atomic / Lazy mirror the Channel arm.
1244                    // Bumps one strong-count share on the shared inner
1245                    // Arc — the outer Arc clone hands out a fresh
1246                    // endpoint of the same protected cell (Mutex/Lazy)
1247                    // or shares observation of the same atomic
1248                    // (Atomic). Interior state is NOT cloned.
1249                    HeapKind::Mutex => {
1250                        Arc::increment_strong_count(bits as *const MutexData);
1251                    }
1252                    HeapKind::Atomic => {
1253                        Arc::increment_strong_count(bits as *const AtomicData);
1254                    }
1255                    HeapKind::Lazy => {
1256                        Arc::increment_strong_count(bits as *const LazyData);
1257                    }
1258                    HeapKind::Decimal => {
1259                        Arc::increment_strong_count(bits as *const rust_decimal::Decimal);
1260                    }
1261                    HeapKind::BigInt => {
1262                        Arc::increment_strong_count(bits as *const i64);
1263                    }
1264                    HeapKind::DataTable => {
1265                        Arc::increment_strong_count(
1266                            bits as *const crate::datatable::DataTable,
1267                        );
1268                    }
1269                    HeapKind::IoHandle => {
1270                        Arc::increment_strong_count(bits as *const IoHandleData);
1271                    }
1272                    HeapKind::NativeView => {
1273                        Arc::increment_strong_count(bits as *const NativeViewData);
1274                    }
1275                    HeapKind::Content => {
1276                        Arc::increment_strong_count(
1277                            bits as *const crate::content::ContentNode,
1278                        );
1279                    }
1280                    HeapKind::Instant => {
1281                        Arc::increment_strong_count(bits as *const std::time::Instant);
1282                    }
1283                    HeapKind::Temporal => {
1284                        Arc::increment_strong_count(bits as *const TemporalData);
1285                    }
1286                    HeapKind::TableView => {
1287                        Arc::increment_strong_count(bits as *const TableViewData);
1288                    }
1289                    HeapKind::TaskGroup => {
1290                        Arc::increment_strong_count(bits as *const TaskGroupData);
1291                    }
1292                    // Wave-γ G-heap-filter-expr (ADR-006 §2.3 / §2.7.6 / Q8
1293                    // amendment): FilterExpr-kinded clone bumps the
1294                    // `Arc<FilterNode>` strong-count exactly once. Mirrors
1295                    // the Drop arm above.
1296                    HeapKind::FilterExpr => {
1297                        Arc::increment_strong_count(bits as *const FilterNode);
1298                    }
1299                    // Wave 8 W8-T26 (ADR-006 §2.7.13 / Q14, 2026-05-10):
1300                    // mirror of the Drop Reference arm above. Bumps one
1301                    // `Arc<RefTarget>` strong-count share — slot bits are
1302                    // `Arc::into_raw(Arc<RefTarget>)` directly per
1303                    // §2.7.13's pure-discriminator-style dispatch.
1304                    HeapKind::Reference => {
1305                        Arc::increment_strong_count(bits as *const RefTarget);
1306                    }
1307                    // W13-iterator-state (ADR-006 §2.7.16 / Q17,
1308                    // 2026-05-10): mirror of the Drop Iterator arm
1309                    // above. Bumps one `Arc<IteratorState>`
1310                    // strong-count share — slot bits are
1311                    // `Arc::into_raw(Arc<IteratorState>)` directly per
1312                    // §2.7.16's typed-Arc dispatch.
1313                    HeapKind::Iterator => {
1314                        Arc::increment_strong_count(bits as *const IteratorState);
1315                    }
1316                    // Wave 15 W15-priority-queue (ADR-006 §2.7.18 / Q19,
1317                    // 2026-05-10): mirror of the HashSet arm. Bumps one
1318                    // `Arc<PriorityQueueData>` strong-count share —
1319                    // PriorityQueue is a HashSet sibling per §2.7.18,
1320                    // full-`HeapValue` arm.
1321                    HeapKind::PriorityQueue => {
1322                        Arc::increment_strong_count(bits as *const PriorityQueueData);
1323                    }
1324                    // W15-range (ADR-006 §2.7.23 / Q24, 2026-05-10):
1325                    // mirror of the Drop Range arm above. Bumps one
1326                    // `Arc<RangeData>` strong-count share — slot bits
1327                    // are `Arc::into_raw(Arc<RangeData>)` directly per
1328                    // §2.7.23's typed-Arc dispatch (mirror of HashMap /
1329                    // HashSet / Iterator).
1330                    HeapKind::Range => {
1331                        Arc::increment_strong_count(bits as *const RangeData);
1332                    }
1333                    // Wave 14 W14-variant-codegen (ADR-006 §2.7.17 / Q18,
1334                    // 2026-05-10): mirror of the Drop arm above. Bumps
1335                    // one `Arc<ResultData>` / `Arc<OptionData>`
1336                    // strong-count share.
1337                    HeapKind::Result => {
1338                        Arc::increment_strong_count(bits as *const ResultData);
1339                    }
1340                    HeapKind::Option => {
1341                        Arc::increment_strong_count(bits as *const OptionData);
1342                    }
1343                    // Char: inline-scalar payload (codepoint bits). Clone
1344                    // is a no-op (Rust copies the slot bits below).
1345                    HeapKind::Char => {
1346                        // No-op: inline-scalar payload.
1347                    }
1348                    // Round 2.5b W7-closure-retain-parallel (ADR-006
1349                    // §2.7.11 / Q12, 2026-05-09 — lockstep with vm-tier
1350                    // Round 2.5 close `5fa4b19`): mirror of the Drop
1351                    // arm above. Bumps one `Arc<HeapValue>`
1352                    // strong-count share — the slot bits are
1353                    // `Arc::into_raw(Arc<HeapValue>)` pointing to a
1354                    // `HeapValue::ClosureRaw(OwnedClosureBlock)` arm.
1355                    // The §2.7.11 dispatch shell duplicates closure-
1356                    // bearing `KindedSlot` carriers (e.g. when a
1357                    // closure value is shared into multiple call
1358                    // sites); each clone owes one matching strong-
1359                    // count bump.
1360                    HeapKind::Closure => {
1361                        Arc::increment_strong_count(bits as *const HeapValue);
1362                    }
1363                    // `Ptr(HeapKind::Future)` carries the future-id u64
1364                    // directly in `bits` — Rust copies the slot bits
1365                    // below; no refcount work. Mirror of the Drop arm.
1366                    HeapKind::Future => {
1367                        // No-op: future-id inline scalar.
1368                    }
1369                    // W17-comptime-vm-dispatch (ADR-006 §2.7.26, 2026-05-12):
1370                    // mirror of the Drop arm — module-fn-id is an
1371                    // inline scalar payload; Rust copies the slot bits
1372                    // below; no refcount work.
1373                    HeapKind::ModuleFn => {
1374                        // No-op: module-fn-id inline scalar.
1375                    }
1376                    // Wave 8 W8-T25 (ADR-006 §2.7.12 / Q13 amendment,
1377                    // 2026-05-10): mirror of the Drop arm above. Bumps
1378                    // one `Arc<SharedCell>` strong-count share — the
1379                    // slot bits are `Arc::into_raw(Arc<SharedCell>)`
1380                    // pointing to a closure-capture / module-binding /
1381                    // local-slot SharedCell. Carriers that duplicate
1382                    // `KindedSlot` (e.g. `read_owned_kinded` on a stack
1383                    // slot whose kind is SharedCell) owe one matching
1384                    // strong-count bump.
1385                    HeapKind::SharedCell => {
1386                        Arc::increment_strong_count(
1387                            bits as *const crate::v2::closure_layout::SharedCell,
1388                        );
1389                    }
1390                    // ADR-006 §2.7.22 amendment (Round 18 S3, 2026-05-13):
1391                    // mirror of the Drop arm above. Bumps one
1392                    // `Arc<MatrixData>` / `Arc<MatrixSliceData>`
1393                    // strong-count share. Typed-Arc pure-discriminator
1394                    // dispatch.
1395                    HeapKind::Matrix => {
1396                        Arc::increment_strong_count(bits as *const MatrixData);
1397                    }
1398                    HeapKind::MatrixSlice => {
1399                        Arc::increment_strong_count(bits as *const MatrixSliceData);
1400                    }
1401                    // `HeapKind::NativeScalar` kinded carrier pending
1402                    // phase-2c kinded redesign (ADR-006 §2.7.4). When
1403                    // it lands, this arm wires its retain per the
1404                    // chosen share carrier. Until then, a non-zero
1405                    // pointer with this kind is a construction-side
1406                    // bug — no Bool-default fallback (forbidden #9).
1407                    HeapKind::NativeScalar => {
1408                        debug_assert!(
1409                            false,
1410                            "KindedSlot::clone: NativeScalar kinded carrier pending \
1411                             phase-2c kinded redesign (ADR-006 §2.7.4)"
1412                        );
1413                    }
1414                },
1415                // Inline scalars: nothing to bump.
1416                NativeKind::Float64
1417                | NativeKind::NullableFloat64
1418                | NativeKind::Int8
1419                | NativeKind::NullableInt8
1420                | NativeKind::UInt8
1421                | NativeKind::NullableUInt8
1422                | NativeKind::Int16
1423                | NativeKind::NullableInt16
1424                | NativeKind::UInt16
1425                | NativeKind::NullableUInt16
1426                | NativeKind::Int32
1427                | NativeKind::NullableInt32
1428                | NativeKind::UInt32
1429                | NativeKind::NullableUInt32
1430                | NativeKind::Int64
1431                | NativeKind::NullableInt64
1432                | NativeKind::UInt64
1433                | NativeKind::NullableUInt64
1434                | NativeKind::IntSize
1435                | NativeKind::NullableIntSize
1436                | NativeKind::UIntSize
1437                | NativeKind::NullableUIntSize
1438                | NativeKind::Bool
1439                // Round 19 S1.5 W12-nativekind-scalar-additions
1440                // (2026-05-14): Float32 + Char are inline 4-byte scalars
1441                // per ADR-006 §2.7.5 amendment. No `Arc<T>` payload, no
1442                // refcount work. Slot bits are the raw f32 bit pattern
1443                // / `c as u32` zero-extended into the low 32 bits.
1444                | NativeKind::Float32
1445                | NativeKind::Char
1446                // R5b-2-bool-null-sentinel-cluster (ADR-006 §2.7 +
1447                // §2.7.5 + §2.7.7/Q9, 2026-05-19): `NativeKind::Null`
1448                // is a non-parametric absence-of-value sentinel — no
1449                // Arc<T> payload, no refcount work.
1450                | NativeKind::Null => {}
1451            }
1452        }
1453        Self {
1454            slot: self.slot,
1455            kind: self.kind,
1456        }
1457    }
1458}
1459
1460#[cfg(test)]
1461mod tests {
1462    use super::*;
1463
1464    /// ADR-006 §2.7: dropping a `String`-kind `KindedSlot` retires the
1465    /// final strong-count share, deallocating the inner `Arc<String>`.
1466    #[test]
1467    fn drop_string_kind_retires_arc() {
1468        let arc = Arc::new("hello".to_string());
1469        let weak = Arc::downgrade(&arc);
1470        let slot = KindedSlot::from_string_arc(arc);
1471        assert_eq!(weak.strong_count(), 1, "slot owns the only strong share");
1472        drop(slot);
1473        assert_eq!(
1474            weak.strong_count(),
1475            0,
1476            "Drop dispatched and decremented refcount"
1477        );
1478    }
1479
1480    /// ADR-006 §2.7: cloning a `KindedSlot` bumps the underlying refcount;
1481    /// dropping both clones retires it cleanly.
1482    ///
1483    /// W5 v0.3 fix (2026-05-17): migrated to the v2-raw `_new` carrier per
1484    /// the same rationale as `executor/objects/property_access.rs::
1485    /// length_typed_object_empty`. The post-Wave-2-D1 `KindedSlot::Clone`
1486    /// / `Drop` dispatch for `Ptr(HeapKind::TypedObject)` uses
1487    /// `v2_retain` / `release_elem` (HeapElement trait) against the
1488    /// embedded `HeapHeader`, NOT `Arc::increment/decrement_strong_count`.
1489    /// Pushing Arc-allocated bits through the v2-raw dispatch attempts
1490    /// `std::alloc::dealloc` with `Layout::new::<TypedObjectStorage>` on
1491    /// an `Arc::into_raw`'d pointer at refcount=0 — a wrong-allocator-pair
1492    /// free that surfaces as `free(): invalid size` SIGABRT.
1493    ///
1494    /// The test now observes the v2-raw refcount through
1495    /// `(*ptr).header.refcount` directly — the canonical way to inspect
1496    /// a `_new`-allocated TypedObject's share count. The Arc-based
1497    /// `weak.strong_count()` probe is incompatible with v2-raw memory
1498    /// (no `ArcInner` header) so the migration replaces it.
1499    #[test]
1500    fn clone_then_double_drop_balances_refcount() {
1501        use std::sync::atomic::Ordering;
1502        // SAFETY block: the entire test sequences raw-pointer
1503        // allocations, refcount inspections, and drop dispatch through
1504        // the v2-raw HeapElement trait. The pointer is allocated via
1505        // `_new` (refcount=1), borrowed transiently for refcount reads,
1506        // and finally retired by the second Drop reaching refcount=0
1507        // (which runs `_drop` to dealloc).
1508        unsafe {
1509            let ptr = TypedObjectStorage::_new(
1510                0,
1511                Vec::<ValueSlot>::new().into_boxed_slice(),
1512                0,
1513                Arc::from(Vec::<NativeKind>::new().into_boxed_slice()),
1514            );
1515            let header_refcount =
1516                |p: *const TypedObjectStorage| (*p).header.refcount.load(Ordering::SeqCst);
1517
1518            assert_eq!(header_refcount(ptr), 1, "_new starts at refcount 1");
1519            let slot1 = KindedSlot::from_typed_object_raw(ptr);
1520            assert_eq!(header_refcount(ptr), 1, "from_typed_object_raw transfers existing share");
1521            let slot2 = slot1.clone();
1522            assert_eq!(header_refcount(ptr), 2, "Clone bumped refcount");
1523            drop(slot1);
1524            assert_eq!(header_refcount(ptr), 1, "first Drop retired one share");
1525            // slot2's Drop retires the final share and runs _drop; the
1526            // pointer is dangling after this line (no further reads).
1527            drop(slot2);
1528        }
1529    }
1530
1531    /// `Vec<KindedSlot>` push + pop + clone must preserve refcount
1532    /// discipline. Without explicit `Drop`/`Clone`, this would alias-copy
1533    /// the heap pointer (WB2.4 / WB2.5 bug class).
1534    #[test]
1535    fn vec_push_pop_clone_balanced() {
1536        let arc = Arc::new("vec test".to_string());
1537        let weak = Arc::downgrade(&arc);
1538        let mut v: Vec<KindedSlot> = Vec::new();
1539        v.push(KindedSlot::from_string_arc(arc));
1540        assert_eq!(weak.strong_count(), 1);
1541        // Clone the Vec — every element clones independently.
1542        let v2 = v.clone();
1543        assert_eq!(weak.strong_count(), 2);
1544        // Pop drops the popped element when it goes out of scope.
1545        {
1546            let _popped = v.pop().expect("vec has one element");
1547            // _popped is alive here — refcount stays 2.
1548            assert_eq!(weak.strong_count(), 2);
1549        }
1550        // After the block, _popped dropped → refcount → 1.
1551        assert_eq!(weak.strong_count(), 1);
1552        drop(v2);
1553        assert_eq!(weak.strong_count(), 0);
1554    }
1555
1556    /// Inline-scalar kinds (Int64, Bool, Float64) have no refcount
1557    /// payload; Drop and Clone are no-ops on the bits.
1558    #[test]
1559    fn inline_scalars_no_refcount() {
1560        let s1 = KindedSlot::from_int(42);
1561        let s2 = s1.clone();
1562        assert_eq!(s1.slot.as_i64(), 42);
1563        assert_eq!(s2.slot.as_i64(), 42);
1564        let b = KindedSlot::from_bool(true);
1565        assert!(b.slot.as_bool());
1566        let n = KindedSlot::from_number(3.14);
1567        assert_eq!(n.slot.as_f64(), 3.14);
1568        // No leak / double-free; would fail under miri otherwise.
1569    }
1570
1571    /// `KindedSlot::none()` is the conventional null carrier — Drop is a
1572    /// no-op (zero bits, Bool kind).
1573    #[test]
1574    fn none_drop_safe() {
1575        let n = KindedSlot::none();
1576        assert_eq!(n.slot.raw(), 0);
1577        drop(n);
1578    }
1579
1580    /// Wave 2 Agent D1 (2026-05-14): the new
1581    /// `KindedSlot::from_typed_object_raw` constructor stores a
1582    /// `*const TypedObjectStorage` pointer (v2-raw carrier; refcount on the
1583    /// on-header). The slot carries the `NativeKind::Ptr(HeapKind::TypedObject)`
1584    /// kind; bits are the raw pointer value. This test exercises the
1585    /// constructor + slot-bit round-trip; Drop semantics for the raw-pointer
1586    /// path are exercised by the `heap_value` module's
1587    /// `heap_element_release_elem_*` tests since `KindedSlot::Drop` still
1588    /// dispatches Arc-style (the Wave-2-pre-D2 transitional bit-shape).
1589    #[test]
1590    fn from_typed_object_raw_constructor_kind_and_bits() {
1591        let kinds: Arc<[NativeKind]> = Arc::from(vec![NativeKind::Int64]);
1592        unsafe {
1593            let ptr = TypedObjectStorage::_new(
1594                99,
1595                vec![ValueSlot::from_int(0)].into_boxed_slice(),
1596                0,
1597                kinds,
1598            );
1599            // Construct via the v2-raw constructor; assert the kind label
1600            // and slot bits.
1601            let slot = KindedSlot::from_typed_object_raw(ptr);
1602            assert_eq!(slot.kind, NativeKind::Ptr(HeapKind::TypedObject));
1603            assert_eq!(slot.slot.raw(), ptr as u64);
1604            // The raw-pointer carrier owns the refcount independently; we
1605            // leak the slot here (don't drop it through the Arc-style
1606            // KindedSlot::Drop arms) and clean up via `_drop`. D2 wires the
1607            // dispatch arms to v2_release; pre-D2 this constructor's slot
1608            // bits MUST NOT flow into Arc-style dispatch (Drop or
1609            // clone_with_kind on these bits would call
1610            // Arc::decrement_strong_count on a non-Arc pointer →
1611            // segfault / heap corruption). Test exits via mem::forget +
1612            // explicit _drop.
1613            std::mem::forget(slot);
1614            TypedObjectStorage::_drop(ptr);
1615        }
1616    }
1617
1618    // ── §2.7.6 / Q8 scalar accessor coverage ──────────────────────────────
1619    //
1620    // One test per scalar accessor: same-kind returns Some, different-kind
1621    // returns None. These tests pin the `KindedSlot` carrier API bound:
1622    // accessors discriminate on `self.kind` and never decode bits when the
1623    // kind is wrong.
1624
1625    #[test]
1626    fn kinded_slot_as_i64_int_returns_some_value() {
1627        let s = KindedSlot::from_int(42);
1628        assert_eq!(s.as_i64(), Some(42));
1629    }
1630
1631    #[test]
1632    fn kinded_slot_as_i64_float_returns_none() {
1633        let s = KindedSlot::from_number(3.14);
1634        assert_eq!(s.as_i64(), None);
1635    }
1636
1637    #[test]
1638    fn kinded_slot_as_f64_float_returns_some_value() {
1639        let s = KindedSlot::from_number(3.14);
1640        assert_eq!(s.as_f64(), Some(3.14));
1641    }
1642
1643    #[test]
1644    fn kinded_slot_as_f64_int_returns_none() {
1645        let s = KindedSlot::from_int(42);
1646        assert_eq!(s.as_f64(), None);
1647    }
1648
1649    #[test]
1650    fn kinded_slot_as_bool_bool_returns_some_value() {
1651        let t = KindedSlot::from_bool(true);
1652        let f = KindedSlot::from_bool(false);
1653        assert_eq!(t.as_bool(), Some(true));
1654        assert_eq!(f.as_bool(), Some(false));
1655    }
1656
1657    #[test]
1658    fn kinded_slot_as_bool_int_returns_none() {
1659        let s = KindedSlot::from_int(1);
1660        assert_eq!(s.as_bool(), None);
1661    }
1662
1663    #[test]
1664    fn kinded_slot_as_char_char_returns_some_value() {
1665        let s = KindedSlot::from_char('A');
1666        assert_eq!(s.as_char(), Some('A'));
1667        // Unicode round-trip.
1668        let s2 = KindedSlot::from_char('λ');
1669        assert_eq!(s2.as_char(), Some('λ'));
1670    }
1671
1672    #[test]
1673    fn kinded_slot_as_char_int_returns_none() {
1674        let s = KindedSlot::from_int(65);
1675        assert_eq!(s.as_char(), None);
1676    }
1677
1678    #[test]
1679    fn kinded_slot_as_char_drop_safe() {
1680        // `from_char` stores codepoint bits inline; Drop must NOT try to
1681        // free them as if they were an `Arc<T>` pointer. Failure mode is
1682        // a debug-assert under the previous Char arm, or a free of an
1683        // invalid pointer in release.
1684        let s = KindedSlot::from_char('Z');
1685        drop(s);
1686    }
1687
1688    #[test]
1689    fn kinded_slot_as_str_string_returns_some_value() {
1690        let s = KindedSlot::from_string_arc(Arc::new("hello".to_string()));
1691        assert_eq!(s.as_str(), Some("hello"));
1692    }
1693
1694    #[test]
1695    fn kinded_slot_as_str_int_returns_none() {
1696        let s = KindedSlot::from_int(42);
1697        assert_eq!(s.as_str(), None);
1698    }
1699
1700    #[test]
1701    fn kinded_slot_from_string_borrows_back() {
1702        // `from_string(&str)` allocates an Arc<String> and stores its
1703        // pointer; `as_str()` should round-trip the contents.
1704        let s = KindedSlot::from_string("round trip");
1705        assert_eq!(s.as_str(), Some("round trip"));
1706    }
1707
1708    // ── §2.7.6 / Q8 from_temporal / from_instant constructor pair ────────
1709    //
1710    // W17-from-temporal-instant-constructors (Wave 3, 2026-05-12). These
1711    // pin the bounded-carrier-API rule: one constructor per `NativeKind`
1712    // heap variant, no parallel discrimination. Both constructors share
1713    // the `Arc::into_raw` typed-Arc shape with the existing Drop / Clone
1714    // arms for `HeapKind::Temporal` / `HeapKind::Instant`.
1715
1716    #[test]
1717    fn kinded_slot_from_temporal_sets_kind_and_retires_arc() {
1718        use crate::heap_value::TemporalData;
1719        let arc = Arc::new(TemporalData::TimeSpan(chrono::Duration::seconds(7)));
1720        let weak = Arc::downgrade(&arc);
1721        let slot = KindedSlot::from_temporal(arc);
1722        assert_eq!(slot.kind(), NativeKind::Ptr(HeapKind::Temporal));
1723        assert_eq!(weak.strong_count(), 1, "slot owns the only strong share");
1724        drop(slot);
1725        assert_eq!(
1726            weak.strong_count(),
1727            0,
1728            "Drop dispatched HeapKind::Temporal arm and retired refcount"
1729        );
1730    }
1731
1732    #[test]
1733    fn kinded_slot_from_temporal_clone_then_double_drop_balances() {
1734        use crate::heap_value::TemporalData;
1735        let arc = Arc::new(TemporalData::TimeSpan(chrono::Duration::milliseconds(500)));
1736        let weak = Arc::downgrade(&arc);
1737        let slot1 = KindedSlot::from_temporal(arc);
1738        assert_eq!(weak.strong_count(), 1);
1739        let slot2 = slot1.clone();
1740        assert_eq!(weak.strong_count(), 2, "Clone bumped refcount");
1741        drop(slot1);
1742        assert_eq!(weak.strong_count(), 1, "first Drop retired one share");
1743        drop(slot2);
1744        assert_eq!(weak.strong_count(), 0, "second Drop retired the last");
1745    }
1746
1747    #[test]
1748    fn kinded_slot_from_instant_sets_kind_and_retires_arc() {
1749        let arc = Arc::new(std::time::Instant::now());
1750        let weak = Arc::downgrade(&arc);
1751        let slot = KindedSlot::from_instant(arc);
1752        assert_eq!(slot.kind(), NativeKind::Ptr(HeapKind::Instant));
1753        assert_eq!(weak.strong_count(), 1, "slot owns the only strong share");
1754        drop(slot);
1755        assert_eq!(
1756            weak.strong_count(),
1757            0,
1758            "Drop dispatched HeapKind::Instant arm and retired refcount"
1759        );
1760    }
1761
1762    #[test]
1763    fn kinded_slot_from_instant_clone_then_double_drop_balances() {
1764        let arc = Arc::new(std::time::Instant::now());
1765        let weak = Arc::downgrade(&arc);
1766        let slot1 = KindedSlot::from_instant(arc);
1767        assert_eq!(weak.strong_count(), 1);
1768        let slot2 = slot1.clone();
1769        assert_eq!(weak.strong_count(), 2, "Clone bumped refcount");
1770        drop(slot1);
1771        assert_eq!(weak.strong_count(), 1, "first Drop retired one share");
1772        drop(slot2);
1773        assert_eq!(weak.strong_count(), 0, "second Drop retired the last");
1774    }
1775}