refactor(device): share one pending-restore token between capture and host switch
`capture_restore.rs` and `host_switch/restore.rs` each defined
`RetiredChannelPolicy`, a token holding the route, a `Weak` to the retired
channel and that policy, an `allow_current_channel`, and a `retry` that was
identical up to the one call that writes the controls back. Around it each
had the same `*SessionFailure { clean, with_pending, into_parts, From }` and a
`rollback_*_start`.
`session::restore` owns that once: `PendingRestore<P>`, `RestoreOutcome<P>`,
`SessionFailure<E, P>` and `rollback_start`, generic over a `RestorePlan` that
says what to write. The public names are aliases of them
(`PendingCaptureRestore`, `CaptureSessionOutcome`, `CaptureSessionFailure`,
`PendingHostSwitchRestore`, `HostSwitchRestoreOutcome`,
`HostSwitchSessionFailure`), so the agent does not change.
The two sessions still differ where they did, deliberately:
- a host-switch write is bounded and tried twice, a capture write is one
untimed attempt: that is each plan's `restore_on`
(`HostSwitchRestorePlan` over the unchanged `restore_host_controls`,
`CaptureRestorePlan` over `restore_reporting`);
- a host-switch rollback writes nothing while host I/O is suspended and
returns the ownership instead: that stays in `rollback_host_switch_start`,
which checks the gate and only then delegates to the shared rollback.
Capture's rollback has no such check and uses the shared one directly.
`SessionFailure` boxes its token. Nesting the plan as its own struct costs the
token eight bytes of padding, which took every capture `Result` to clippy's
128-byte `result_large_err` line; the token only rides on a failed rollback.
Guard: device-pending-restore-owner flags a second `RetiredChannelPolicy` or a
`Weak` taken from a shared channel outside session/restore.rs (4 hits on the
parent tree, 0 here). A
AprilNEA committed
f412a1a2dc0058f5f0aa6cf9c676bda70e4f9408
Parent: bad0011