Skip to main content

ClosureLayout

Struct ClosureLayout 

Source
pub struct ClosureLayout {
    pub capture_types: Vec<ConcreteType>,
    pub captures: Vec<FieldInfo>,
    pub capture_kinds: Vec<CaptureKind>,
    pub capture_native_kinds: Vec<NativeKind>,
    pub heap_capture_mask: u64,
    pub owned_mutable_capture_mask: u64,
    pub shared_capture_mask: u64,
    pub captures_size: usize,
    pub captures_align: usize,
}
Expand description

Computed layout for a closure’s captures.

Offsets in captures are relative to the captures area start (i.e. offset 0 = first byte after the header). Use ClosureLayout::heap_capture_offset or ClosureLayout::stack_capture_offset for absolute offsets from the corresponding closure base pointer.

§ADR-006 §2.7.8 / Q10 — per-capture NativeKind companion

capture_native_kinds extends the §2.7.7 stack-side parallel-Vec<NativeKind> invariant to closure cell storage. Each entry is the NativeKind interpretation of capture slot i’s 8-byte raw payload — set at construction (lockstep with capture_types[i] and capture_kinds[i]), read at access/teardown so that drop dispatch routes through drop_with_kind(bits, kind) (the canonical KindedSlot::drop table) instead of the deleted ValueWord-shape vw_drop(bits) (forbidden #8 per §2.7.7) or the also-deleted Arc<HeapValue> blanket decrement.

Index invariant: capture_types.len() == capture_native_kinds.len() == capture_kinds.len() == captures.len() at every observable boundary.

Storage location. Per ADR-006 §2.7.8 / Q10, the kinds live in the layout descriptor (constant per ClosureTypeId), NOT in the per-instance raw closure block. The block’s fixed-offset C-shaped byte buffer is unchanged — JIT FFI offsets (SHARED_CELL_VALUE_OFFSET, HEAP_CLOSURE_HEADER_SIZE, per-capture heap_capture_offset(i)) are preserved. The kind track is a pure side-table on the layout, identical in shape to the §2.7.8 ADR example for ClosureCell { bits, kinds } but specialised to the existing OwnedClosureBlock raw-byte form: bits live in the block at layout.heap_capture_offset(i), kinds live in layout.capture_native_kinds[i].

Fields§

§capture_types: Vec<ConcreteType>

The ConcreteType of each capture, in declaration order. Also the registry key for this layout.

§captures: Vec<FieldInfo>

Per-capture field info. offset is relative to the captures area start.

§capture_kinds: Vec<CaptureKind>

Per-capture storage discipline. capture_kinds[i] corresponds to captures[i] and determines which of the three mutually-exclusive masks below (if any) has bit i set.

§capture_native_kinds: Vec<NativeKind>

Per-capture NativeKind companion (ADR-006 §2.7.8 / Q10). Entry i is the kind interpretation of capture slot i’s raw 8-byte payload in the closure block. Lockstep with capture_types / capture_kinds at every observable boundary. Read at access/teardown by drop glue — the cell-store drop_with_kind(bits, kind) dispatch reads this per-capture entry to route to the matching Arc<T>::decrement arm.

The default constructor ClosureLayout::from_capture_types derives this list from capture_types via native_kind_from_concrete_type. The explicit constructor ClosureLayout::from_capture_types_with_native_kinds accepts a caller-supplied list when the kind is finer-grained than what ConcreteType can express (e.g. NativeKind::Ptr(HeapKind::TypedArray) vs the generic Ptr field kind).

§heap_capture_mask: u64

Bitmap: bit N = capture N is a heap-refcounted pointer (Ptr) held directly in the slot (i.e. CaptureKind::Immutable over a Ptr field kind). Used by Drop glue to call release_raw_value_bits on the slot contents.

§owned_mutable_capture_mask: u64

Bitmap: bit N = capture N is CaptureKind::OwnedMutable. The slot holds *mut ValueWord (from Box::into_raw); Drop reclaims via Box::from_raw, which also releases any heap refcount share held inside the boxed ValueWord.

§shared_capture_mask: u64

Bitmap: bit N = capture N is CaptureKind::Shared. The slot holds *const SharedCell (from Arc::into_raw); Drop reclaims via Arc::from_raw, which decrements the strong count by one.

§captures_size: usize

Size in bytes of the captures area (rounded up to 8-byte alignment). Does NOT include the header.

§captures_align: usize

Alignment of the captures area (always 8 in practice).

Implementations§

Source§

impl ClosureLayout

Source

pub fn from_capture_types( capture_types: &[ConcreteType], kinds: &[CaptureKind], ) -> Self

Build a layout from parallel lists of capture types and storage kinds.

Captures are laid out in declaration order with natural alignment padding, starting from offset 0 of the captures area. The total size is rounded up to 8 bytes so the whole closure object is 8-aligned.

For CaptureKind::OwnedMutable / CaptureKind::Shared the slot is always emitted as a FieldKind::Ptr (8-byte pointer), regardless of the underlying ConcreteType — the slot holds the raw *mut ValueWord (Box) or *const SharedCell (Arc), not the value directly. Only CaptureKind::Immutable honours the natural width of capture_types[i].

§Invariants on the emitted masks

The three per-index masks are mutually exclusive: for any index i, at most one of heap_capture_mask, owned_mutable_capture_mask, shared_capture_mask has bit i set. release_typed_closure relies on this to avoid double-releases.

§Panics
  • If capture_types.len() != kinds.len().
  • If capture_types.len() > 64 (mask-width limit).
  • If any capture type is ConcreteType::Void (not a well-formed capture per §2.7.8 / Q10 — see native_kind_from_concrete_type).

capture_native_kinds is derived from capture_types via native_kind_from_concrete_type. Use ClosureLayout::from_capture_types_with_native_kinds when the caller has a finer-grained kind in hand (e.g. distinguishing Ptr(HeapKind::TypedArray) vs Ptr(HeapKind::TypedObject) for two ConcreteType::Pointer(_) captures).

Source

pub fn from_capture_types_with_native_kinds( capture_types: &[ConcreteType], kinds: &[CaptureKind], native_kinds: &[NativeKind], ) -> Self

Build a layout from parallel lists of capture types, storage kinds, and explicit per-capture NativeKinds (ADR-006 §2.7.8 / Q10).

This is the explicit-kinds entry point. The default ClosureLayout::from_capture_types derives the kinds via native_kind_from_concrete_type; use this when the caller knows a finer-grained kind (e.g. specific HeapKind discriminator for a ConcreteType::Pointer(_) capture) or wants to pin the kind track to an authoritative source (e.g. FrameDescriptor.slots[binding_idx] per §2.7.8’s debug cross-check).

§Panics
  • If capture_types.len() != kinds.len() or capture_types.len() != native_kinds.len().
  • If capture_types.len() > 64 (mask-width limit).
Source

pub fn capture_count(&self) -> usize

Number of captures.

Source

pub fn capture_offset(&self, i: usize) -> usize

Offset of capture i from the captures area start (not from the heap / stack base pointer).

Source

pub fn capture_kind(&self, i: usize) -> FieldKind

FieldKind of capture i.

Source

pub fn capture_inner_kind(&self, i: usize) -> FieldKind

Interior FieldKind of capture i — the type stored inside the box/cell, not the slot kind.

For Immutable captures this returns the same value as capture_kind: the slot directly holds a value of the declared type.

For OwnedMutable and Shared captures the slot kind is always FieldKind::Ptr (the slot stores *mut T / *const SharedCell), so capture_kind would lose the underlying type. This method returns the interior type by consulting capture_types[i] directly. Drop glue uses this to reconstruct the typed Box<T> for an OwnedMutable cell.

Source

pub fn heap_capture_offset(&self, i: usize) -> usize

Absolute offset of capture i from the start of a heap-allocated TypedClosureHeader (i.e. add 16 for the header).

Source

pub fn stack_capture_offset(&self, i: usize) -> usize

Absolute offset of capture i from the start of a StackClosure (i.e. add 8 for the function_id/type_id pair).

Source

pub fn total_heap_size(&self) -> usize

Total size of a heap-allocated closure with this layout: HeapHeader + function_id + type_id + captures.

Source

pub fn total_stack_size(&self) -> usize

Total size of a stack-allocated closure with this layout: function_id + type_id + captures.

Source

pub fn is_heap_capture(&self, i: usize) -> bool

Whether capture i is a heap-refcounted pointer (slot-owned Arc share on an immutable Ptr capture).

Source

pub fn is_owned_mutable_capture(&self, i: usize) -> bool

Whether capture i is CaptureKind::OwnedMutable — slot holds *mut ValueWord and must be Box::from_raw’d on drop.

Source

pub fn is_shared_capture(&self, i: usize) -> bool

Whether capture i is CaptureKind::Shared — slot holds *const SharedCell and must be Arc::from_raw’d on drop.

Source

pub fn capture_storage_kind(&self, i: usize) -> CaptureKind

Storage discipline for capture i.

Source

pub fn capture_native_kind(&self, i: usize) -> NativeKind

NativeKind of capture i’s raw 8-byte payload (ADR-006 §2.7.8 / Q10). Used by drop glue to dispatch through drop_with_kind(bits, kind) — the canonical KindedSlot::Drop table — rather than the deleted vw_drop / Arc<HeapValue> blanket-decrement shapes.

For Immutable captures the kind classifies the slot’s payload directly (e.g. Float64 for an f64 capture, String for an Arc<String> capture, Ptr(HeapKind::TypedArray) for an Arc<TypedArrayData> capture).

For OwnedMutable and Shared captures the slot stores a raw *mut T (Box) or *const SharedCell (Arc) cell pointer — the kind classifies the interior payload of that cell (the same shape capture_inner_kind returns at the FieldKind level, but resolved to NativeKind for kind-aware drop dispatch). The per-Arc / per-Box drop helper (drop_owned_mutable_capture / drop_shared_capture) consumes this to release the inner share before reclaiming the cell allocation itself.

Trait Implementations§

Source§

impl Clone for ClosureLayout

Source§

fn clone(&self) -> ClosureLayout

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosureLayout

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Allocation for T
where T: RefUnwindSafe + Send + Sync,