pub struct GuardStore { /* private fields */ }Expand description
Type-erased per-(buffer, mode) Guard storage.
One per App, and in practice always behind a GuardStoreHandle
(the registry’s activation / deactivation methods take the handle, so
the spawned lifecycle task can insert into the same store). Default is
empty.
Not Clone – Box<dyn Any> is not Clone.
M-async.4 epoch counter: each (buffer, mode) key
carries a u64 epoch that monotonically increments on every
activate begin + every deactivate. The dispatcher’s spawn
task captures the epoch when it queues, then validates
against the current epoch via Self::try_insert before
stashing its Guard. A mismatch means a deactivate (or a
later activate) arrived while the spawn was in flight; the
returned Err(stale_guard) lets the spawn drop the Guard
(firing its Drop for out-of-band cleanup) instead of
stashing it in a logically-inactive store slot.
Implementations§
Source§impl GuardStore
impl GuardStore
Sourcepub fn insert(
&mut self,
buffer: BufferId,
mode: ModeId,
guard: Box<dyn Any + Send>,
)
pub fn insert( &mut self, buffer: BufferId, mode: ModeId, guard: Box<dyn Any + Send>, )
Stash a Guard for the given (buffer, mode). Replaces
any existing entry (the old Guard is dropped, firing its
Drop impl). Used in tests + the rare reload path; the
production dispatcher routes through Self::try_insert
to respect the epoch invariant.
Sourcepub fn bump_epoch(&mut self, buffer: BufferId, mode: ModeId) -> u64
pub fn bump_epoch(&mut self, buffer: BufferId, mode: ModeId) -> u64
Bump the epoch for (buffer, mode) and return the new
value. The dispatcher’s sync prefix calls this when
queueing a step; the spawn task captures the returned
value and passes it to Self::try_insert on
completion. Wraps on overflow (u64::MAX → 0); the
dispatcher tolerates this because consecutive bumps
always advance by 1, so a wrap that happens to land on
a stale spawn’s captured epoch would require 2^64
activate / deactivate cycles in flight – not a
realistic concern.
Sourcepub fn current_epoch(&self, buffer: BufferId, mode: ModeId) -> u64
pub fn current_epoch(&self, buffer: BufferId, mode: ModeId) -> u64
Current epoch for (buffer, mode). 0 if the pair has
never had an activation queued. Used by tests + the
dispatcher’s spawn task to validate before stashing.
Sourcepub fn try_insert(
&mut self,
buffer: BufferId,
mode: ModeId,
my_epoch: u64,
guard: Box<dyn Any + Send>,
) -> Result<(), Box<dyn Any + Send>>
pub fn try_insert( &mut self, buffer: BufferId, mode: ModeId, my_epoch: u64, guard: Box<dyn Any + Send>, ) -> Result<(), Box<dyn Any + Send>>
Insert guard only if my_epoch still matches the
store’s current epoch for (buffer, mode). Returns
Ok(()) on success; on epoch mismatch returns
Err(guard) so the caller can drop the Guard outside
the lock (the Box’s Drop then fires the original
type’s cleanup).
Used by the M-async.4 spawn-task path: a deactivate
(or a subsequent activate) arriving while a spawn was
in flight bumps the epoch via Self::remove /
Self::bump_epoch; the spawn’s late try_insert
then fails the match and drops the Guard instead of
stashing it in a logically-inactive store slot.
Sourcepub fn remove(
&mut self,
buffer: BufferId,
mode: ModeId,
) -> Option<Box<dyn Any + Send>>
pub fn remove( &mut self, buffer: BufferId, mode: ModeId, ) -> Option<Box<dyn Any + Send>>
Take ownership of the Guard for (buffer, mode),
bumping the epoch so any in-flight spawn that hasn’t
inserted yet fails its Self::try_insert check.
Returns None if no Guard was stashed.
Sourcepub fn purge_buffer(&mut self, buffer: BufferId)
pub fn purge_buffer(&mut self, buffer: BufferId)
Drop every Guard belonging to buffer. Call when a
buffer is deleted – the dispatcher’s normal
deactivation path may not run if the buffer vanishes
before the App can deactivate its modes. Bumps the
epoch for every (buffer, *) entry so any in-flight
spawn for the purged buffer fails its later
Self::try_insert.