Skip to content

internal/path_c_admit

Internal module

lockfree/internal/path_c_admit is an internal module. Its API is not part of the umbrella's semver contract and may change at any time. Downstream code MUST NOT import it directly. Documented here for contributors and reviewers.

path_c_admit implements the unbounded MPMC "path C — admit" branch of the consumer-side close protocol: the case where the consumer observes an empty cell and must close the cell so that the producer sees the closure and retries on the next segment. See the LCRQ paper §4 for the broader protocol context.

See also

  • path_c_wrap — sibling close-CAS branch.
  • Queue — the body that dispatches into these paths.

path_c_admit

Path-C admission dispatch — the user-facing T type-class gate that sits at the head of every Queue / BQueue push, pop, drain entry point.

Behaviour
  • Path-C string / seq handling (no ManagedSlice indirection).
  • when T is ref: composition matrix (25 rows; verbatim REJECT messages for rows 7 and 8).
  • Nullable T handling (nil passthrough — not a reject).
  • ref T rejection rules (canonical when / elif chain shape).
  • mm:none + ref T contract details (pure bit transport).
  • ManagedRef[X] shim impl details (per-MM inc/dec wrappers).
  • Path-C string / seq inline transfer-ownership: sink string / sink seq[U] flow through the slot's Pair.second half. Per-MM treatment lives at the call site inside the queue's push/pop body; this admission template only validates the type-class.
Why a template, not a when block inlined at every call site

The reject/accept chain repeats VERBATIM at every user-facing push, pop, and drain entry across both queue.nim and bqueue.nim. Inlining it 14+ times would bake the REJECT messages into copies that drift the moment someone updates one and forgets the others. Centralising it in one template makes the matrix the single source of truth.

The template expands to a when chain that emits either a compile-time {.error.} (REJECT rows + unsupported fallback) or expands to nothing (ACCEPT rows).

NOT user-facing

This module is an internal implementation detail. Users see only the Queue / BQueue types and their push/pop/drain APIs.

hasManagedFields compileTime

proc hasManagedFields(T: typedesc): bool
Parameters
  • T (typedesc)
Returns

bool

pathCAdmit

template pathCAdmit(T: typedesc)

Static dispatch / admission gate for Queue[T, ...] and

BQueue[T, ...] push, pop, drain entries.

Emits compile-time {.error.} for the REJECT rows (distinct ref alias row 7, nested ref ref row 8, value types with managed fields) and the unsupported-T fallback. Accept rows (ref T, string, seq[U], POD) expand to nothing; their per-MM lifecycle handling lives at the call site below.

The chain ORDER MATTERS. Reject arms must come BEFORE accept arms so a ref ref Foo does not match the plain T is ref accept arm by way of "outer ref still matches is ref."

Row order verification:

  • T is ref and (T is ref ref ...) reject arm matches nested refs. T is ref plain accept arm fires only for direct ref to a non-ref user type, never for ref ref.
  • T is distinct and distinctBase(T) is ref reject arm matches distinct-of-ref aliases. Plain T is distinct does not match non-distinct types so the downstream T is ref accept arm catches exactly the intended population.

Nullable note: nil for ref T, ptr T, pointer, and cstring is ACCEPTED (slot bits = 0, disambiguated by the seq counter / committed flag at the slot-state predicate layer). The admit chain does NOT reject nil.

Parameters
  • T (typedesc)