refactor(#2500): encapsulate the jobq lock, drop the dead borrowed-guard layer

Make the resource lock unmisusable from outside the crate: the public
surface is now purely declarative (build a Graph with Dep::Resource edges,
configure capacities, run the Scheduler), and the scheduler owns every
acquire/release — a consumer never holds a guard, so it cannot hold the
lock wrong.

- `guard` module + `ResourceTable::try_acquire_all`/`release_all` +
  `Graph::set_state` are now `pub(crate)`.
- Remove the dead borrowed-guard layer (`ResourceGuard::borrowed`,
  `Acq::Borrowed`, `is_owning`): the scheduler tracks re-entrancy via its
  own single borrow slot per (holder, resource) and never constructs a
  borrowed guard, so re-entrancy lives in exactly one place. `Acq`
  collapses into the owning `ResourceGuard` struct.
- `#[must_use]` on `Scheduler::settle` — ignoring its ids silently drops
  runnable work.
- `SharedResources::with` (test-only table observability) is `#[cfg(test)]`.
- Drop the moot borrowed-guard tests; retained owning tests are black-box,
  and the redundant `set_state` test helper is gone.
This commit is contained in:
atlas 2026-07-19 14:40:25 +02:00 committed by mara
commit f64ab47de0
4 changed files with 41 additions and 111 deletions

View file

@ -95,7 +95,7 @@ impl<R: Clone + Eq + Hash> ResourceTable<R> {
/// `false` and leaves the table completely untouched. A request for more
/// units than a name's capacity can therefore never succeed — the scheduler
/// should reject such a node at insert time so it does not wait forever.
pub fn try_acquire_all(&mut self, reqs: &[(R, u32)]) -> bool {
pub(crate) fn try_acquire_all(&mut self, reqs: &[(R, u32)]) -> bool {
let wanted = aggregate(reqs);
// All-or-nothing: bail before mutating if any request cannot be met.
for (name, &count) in &wanted {
@ -113,7 +113,7 @@ impl<R: Clone + Eq + Hash> ResourceTable<R> {
///
/// Duplicate names are summed. Releasing more than is held saturates at zero
/// rather than underflowing, so a double release is harmless.
pub fn release_all(&mut self, reqs: &[(R, u32)]) {
pub(crate) fn release_all(&mut self, reqs: &[(R, u32)]) {
for (name, count) in aggregate(reqs) {
if let Some(h) = self.held.get_mut(name) {
*h = h.saturating_sub(count);