pub struct NeedsBus(/* private fields */);Expand description
Proof that a step needs the bus, produced only by Rdp::tick_without_bus and
consumed only by Rdp::tick_with_bus.
The two halves exist for a caller that cannot hand out a borrow of this struct
without first moving the struct itself — it needs to know whether the step will use
the bus before paying the 344-byte core::mem::take that arranging one costs.
(In this workspace that caller is the Bus, which owns every chip.) The bus half
then has real preconditions:
the pipeline is unfrozen, stall is zero, and the command FIFO is non-empty.
Those preconditions are carried by this token rather than by a comment, an
assert!, or a debug_assert! alone. A comment is not checked; a debug_assert
compiles out, so a release build would decode a command from an empty FIFO in
silence; and a release guard that returns early would make a caller who never calls
tick_without_bus hang, because stall would never count down. Requiring the token
removes all three: calling the bus half out of order does not compile.
The field is private and the type has no constructor, so it cannot be forged.
Dropping a token loses a cycle, not the work. The Some path mutates
nothing — it is reached only once stall is zero, so no decrement has happened, and
no FIFO pointer moves until the bus half runs. The command is therefore still
pending and the next rdp_tick retries the identical step. What is lost is the
step: the RDP made no progress during that GCLK and is one cycle late from then
on. That is the failure mode worth naming here, because it is a timing divergence
with no wrong state anywhere — correct-but-late, which no state comparison can
see. Hence #[must_use], below, rather than a debug_assert on the token count.
What makes ignoring one loud is the #[must_use] on
Rdp::tick_without_bus itself, not the one on this type: an attribute on T
does not propagate through Option<T>, and Option — unlike Result — is not
#[must_use] either. Verified by discarding the call and watching the lint appear
only once the attribute moved to the function.
Copy and Clone are deliberately not derived. Either would let a caller keep
a token past the step it authorized and present it again after the state it attested
to had changed — the same hole as taking it by reference. Debug is derived because
it cannot duplicate the value.