pub trait StackOps<const INDEX_BITS: u32>: StackStorage<INDEX_BITS> {
// Required methods
unsafe fn push_index(&self, index: u32) -> Result<(), TagExhausted>;
fn pop_index(&self) -> Option<u32>;
}Expand description
The stack operations — push_index /
pop_index — blanket-implemented by the crate for every
StackStorage implementor. Downstream impls are impossible (trait
coherence: a second impl would conflict with this blanket), so the
CAS-retry-loop bodies cannot be overridden or drifted from; an implementor
controls only head/load_next/store_next.
Required Methods§
Sourceunsafe fn push_index(&self, index: u32) -> Result<(), TagExhausted>
unsafe fn push_index(&self, index: u32) -> Result<(), TagExhausted>
Push index onto the stack (classic Treiber push with a tag bump).
The current head index (or TAIL when empty) is stored in index’s
link with Release, then the head is CASed to (index, tag + 1).
The numeric guard below is unconditional because an invalid index would
corrupt the free-list and could double-issue a slot.
§Safety
The caller must uphold all three clauses:
indexis in this implementor’s documented link domain: it has a dedicated cell and the hooks are memory-safe for it. The runtimeindex < INDEX_MASKguard checks only the packed-word range, not this possibly narrower domain.indexis not reachable through any binding whose hooks touch the same link cells. It was never pushed, or its latest push was followed by a successfulpop_indexreturning it from any such binding. A stale popper that observed the index but lost its CAS did not pop it and does not block this push; the tag makes that stale CAS fail, and this push overwrites the old link before publishing the index through the receiving binding.- This call owns a unique, unconsumed publish/recycle authority: either a fresh index or one legitimately transferred by a specific successful pop, including a pop through another binding sharing the cells. The authority is consumed at this call’s successful head CAS, not at physical return, so a later popper may republish the index with its own authority before this call returns. Two pushes may not consume the same authority without an intervening successful pop. These liveness and authority obligations are not runtime-checked; violating them can create a cycle or double-issue an index.
§Errors
Returns Err(TagExhausted) without publishing when the current tag
is TaggedIndex::TAG_MAX. The head is then permanently sealed; the
refused index remains the caller’s. A retry may have left stale link
contents, which the next successful push overwrites before publishing.
§Panics
Panics if index >= INDEX_MASK (the empty sentinel is reserved), in both
debug and release. The implementor’s link hooks may enforce a narrower
bound; callers must satisfy that bound too.
Sourcefn pop_index(&self) -> Option<u32>
fn pop_index(&self) -> Option<u32>
Pop the top index off the stack, or None if empty.
Loads the tagged head, reads its next link, and CASes the head to that
link without changing the tag. A popper that loses its CAS retries with
an Acquire observation; the monotonic, sealing tag prevents ABA.
When the popped element is the last one (next == TAIL), the empty
sentinel keeps the observed running tag rather than resetting to zero.
On a lost CAS whose actual head is already empty, retry backoff is
skipped because the next iteration returns None (see the configured
backoff cap).
load_next is reached through this implementor’s binding, whose head is
read once for the whole CAS loop; see StackStorage.
§Panics
Panics if load_next returns neither TAIL nor an index below
INDEX_MASK, or returns the popped index itself. The release-active
guard prevents pack_truncating from turning an invalid value into a
wrong live index or the empty sentinel. A self-loop indicates a caller
contract violation; the guard is a detector, not a repair. Dedicated
link storage is required because a stale popper may read a link after
another thread has popped the index, and payload-aliasing could produce
an arbitrary in-range value that passes this guard silently.
The implementor’s load_next may also panic on its own narrower domain
bound; see StackOps::push_index’s # Panics.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".