Skip to main content

DeferQueue

Struct DeferQueue 

Source
pub struct DeferQueue { /* private fields */ }
Expand description

Owner-only deferred-closure queue (D249/S2c — the minimal Defer split pulled out of CoreMailbox; D254 (S5) relaxed off cross- thread primitives).

Under D248 full single-owner the substrate Sink/TopologySink dropped Send + Sync, so a DeferFn (which captures relaxed Sinks / Rc<RefCell<GraphInner>>) is !Send. It cannot ride the Send + Sync CoreMailbox (that bridges the timer.rs cross-thread Arc<CoreMailbox> post side). This queue is therefore owner-only and !Send: held behind an Rc shared between crate::node::Core and graphrefly-operatorsProducerEmitter on the one owner thread. Drained owner-side by crate::node::Core::drain_mailbox (after the id-mailbox) and the in-wave BatchGuard drain.

Owner-thread-only by construction (D254 (S5), 2026-05-19). The Rc<DeferQueue> is never sent across threads (the closures it holds are !Send), so the cross-thread primitives it used to carry — parking_lot::Mutex<VecDeque<DeferFn>> for q and AtomicBool for runnable — were unused capacity. D254 collapses them to RefCell<VecDeque<DeferFn>> + Cell<bool>, dropping the parking_lot::Mutex::lock acquire on every owner-side post/drain (the hottest D251 path). closed similarly drops to Cell<bool> — it is set by Drop for Core on the owner thread (the only close() call site) and read by post/drain_into on the same thread.

S4 still does the per-group-wake + typed snapshot/prune MailboxOp reshape (D246 rule 8) — D249 is the acknowledged minimal first touch that lets the D248 single-owner Sink relaxation land in S2c.

Implementations§

Source§

impl DeferQueue

Source

pub fn new() -> Self

A fresh, open, empty owner-side defer queue.

Source

pub fn is_runnable(&self) -> bool

Whether the queue currently holds work (the in-wave drain gate). #[must_use] (/qa m4) — a discarded result silently loses the drain-gate signal.

Source

pub fn post(&self, f: DeferFn) -> bool

Enqueue an owner-side deferred closure. Returns false iff the owning Core has dropped (Self::close) — the caller’s closure is dropped unrun (same contract as the old CoreMailbox::post_defer). Owner-thread-only by D248/D249 construction — see the struct doc; no cross-thread TOCTOU against close is possible because both run on the one owner thread and never overlap.

#[must_use] (/qa m3) — false is the load-bearing signal that the caller’s closure was dropped unrun; ignoring it can mask teardown races where work was silently discarded.

Source

pub fn drain_into(&self, max_ops: u32, apply: impl FnMut(DeferFn))

Owner-side drain. Pops every queued closure FIFO and applies it (re-entrancy-safe: a closure may re-post; a later drain picks it up). max_ops bounds one drain against a self-re-posting livelock (mirrors CoreMailbox::drain_into).

Re-entry note (/qa M6). Under the pre-D254 parking_lot::Mutex<VecDeque<DeferFn>> shape, an owner-thread re-entrant drain_into from inside apply(f) would have deadlocked at the inner lock acquire. Under the D254 RefCell<VecDeque<DeferFn>> shape it would panic with BorrowMutError instead — different failure mode, same fail-loud outcome. In practice the pre-D254 design never had any in-tree re-entrant drain caller (the embedder pump’s drain_mailbox is never invoked recursively from within an apply closure body — drain_mailbox is the embedder seam, not a DeferFn capture target), so neither failure mode is reachable from in-tree code. Documented for any future binding that might construct one.

§Panics

Panics if a single drain applies max_ops closures — a Defer closure re-posting itself every application (owner-side livelock), the defer-queue analogue of a fn that emits to itself.

Source

pub fn close(&self)

Mark the owning Core gone. Idempotent.

Drop timing of queued closures (QA, 2026-05-19). This method only flips closed so subsequent post calls drop their closures unrun (closed == true short-circuits enqueue) and running CoreFull on a half-dropped Core is structurally impossible. The already-queued closures are NOT drained here; they remain in q and are dropped when the last Rc<DeferQueue> clone drops (every ProducerEmitter / graph reactive handle holds one — D249). Since closures by contract capture no HandleId (D235 P8 / D246 r8 sites), this is leak-free for refcount purposes; callers MUST honour the no-HandleId-in- DeferFn discipline (see DeferFn’s doc) for this to hold.

Trait Implementations§

Source§

impl Default for DeferQueue

Source§

fn default() -> Self

Returns the “default value” for a type. 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> 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> Same for T

Source§

type Output = T

Should always be Self
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.