Skip to content

ManagedSlice

ManagedSlice[T] is a single-owner, move-tracked, contiguous allocation of T elements with an explicit length. It is the managed-payload analog of ManagedRef[T] for arrays.

ManagedSlice is the recommended payload type when queueing batched / array-shaped work that must outlive the producer's stack frame and cannot be passed as ptr T because the consumer needs the length too. Like ManagedRef, it integrates with the umbrella's SMR (nebr) for deferred reclamation.

See also

managed_slice

lockfree/managed_slice

Internal slot encoding for string and seq[U] payloads under Path C (Queue[string, ...] / Queue[seq[U], ...]). Unified encoding using the heap-box pattern.

NEVER user-facing

ManagedSlice[T] is the wire-format the queue stores in its slot array. The user-facing API is string / seq[U]. ManagedSlice MUST NOT leak into public docs, examples, or signatures.

Design pattern: heap-boxed payload pointer

The slot bits are a distinct uint pointer at a heap-allocated box (alloc0Shared) that holds the V2 payload (NimStringV2 / NimSeqV2[U]). Box layout deliberately mirrors a ptr object with a single v field of the payload type so that under arc/orc/atomicArc/refc the compiler-emitted destructor for v runs the V2 frees() path automatically when =destroy is called explicitly in disposeSlot.

Path C MM matrix
  • arc / orc / atomicArc / refc — sink-assign payload into the zero-initialised box on wrap (compiler emits =sink); move the payload out and deallocShared the box on unwrap; =destroy the box payload + deallocShared the box on disposeSlot (destructor walk).
  • none — strict bit-transport contract. The source binding is NOT zeroed on wrap and the destination is NOT destroyed on disposeSlot. The user owns lifetime; we are a pointer-bit transport only.
ABI stability

sizeof(ManagedSlice[T]) == sizeof(uint) on every supported platform — asserted at compile time in the static: block below.

ManagedSlice

type ManagedSlice[T] = distinct uint

Slot encoding for a string (T = char) or seq[U]

(T = U) payload. Internal — see module doc-comment. Sized and aligned identically to uint.

wrap inline

proc wrap(s: sink string): ManagedSlice[char]

Pack a string into the slot encoding. Allocates a shared

heap box and transfers the payload in. The caller's binding is consumed (sink).

Parameters
  • s (sink string)
Returns

ManagedSlice[char]

wrap inline

proc wrap(s: sink seq[U]): ManagedSlice[U]

Pack a seq[U] into the slot encoding. Allocates a shared

heap box and transfers the payload in.

seq[ref U] and seq[seq[U]] are ACCEPTED. The box-pattern transport handles inner-element lifecycle correctly via Nim's compiler-emitted seq =destroy when the box is reconstructed at pop or destroy-walk. The library's transport is the outer seq value (boxed here); inner refs/seqs are the seq's lifecycle problem. No supportsCopyMem(U) guard is applied here or in path_c_admit.nim.

Parameters
  • s (sink seq[U])
Returns

ManagedSlice[U]

unwrap inline

proc unwrap(ms: ManagedSlice[char]): string

Unpack a string from the slot encoding. Frees the heap box.

On arc/orc/atomicArc/refc the payload pointer is moved out (no refcount bump on the V2 payload); on mm:none the payload bits are copied out and the source bits are not zeroed.

Parameters
  • ms (ManagedSlice[char])
Returns

string

unwrapSeq inline

proc unwrapSeq(ms: ManagedSlice[U]): seq[U]

Unpack a seq[U] from the slot encoding. Frees the heap box.

Distinctly named (unwrapSeq, not unwrap) so the seq path is never shadowed by the non-generic unwrap(ManagedSlice[char]) (string/StringBox) overload. ManagedSlice[char] is the slot encoding for BOTH string (T = char) and seq[char] (U = char); they collapse to the same instantiation, so Nim overload resolution would pick the non-generic string unwrap for a seq[char] slot, applying the StringBox layout to a SeqBox. The distinct name forces the SeqBox path explicitly. See internal/path_c_wrap.nim.

Parameters
  • ms (ManagedSlice[U])
Returns

seq[U]

disposeSlot inline

proc disposeSlot(ms: ManagedSlice[char])

Destroy-walk dispose for an unpopped string slot. Safe on the

nil slot (0).

Non-generic (string / StringBox) overload. disposeSeqSlot is the distinctly-named SEQ counterpart so a seq[char] slot is never routed here by overload resolution (StringBox vs SeqBox layout). See internal/path_c_wrap.nim.

Parameters
  • ms (ManagedSlice[char])

disposeSeqSlot inline

proc disposeSeqSlot(ms: ManagedSlice[U])

Destroy-walk dispose for an unpopped seq slot. Safe on the nil

slot (0).

Distinctly named (disposeSeqSlot, not disposeSlot) so the seq path is never shadowed by the non-generic disposeSlot(ManagedSlice[char]) (string/StringBox) overload. ManagedSlice[char] is the slot encoding for BOTH string and seq[char]; they collapse to the same instantiation, so Nim overload resolution would pick the non-generic string disposeSlot for a seq[char] slot, running the StringBox destructor over a SeqBox. The distinct name forces the SeqBox path explicitly. See internal/path_c_wrap.nim.

Parameters
  • ms (ManagedSlice[U])