We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← The Expert Edge: Idiom, Review and Capstones step 5 of 14
Capstone: an ownership-only job scheduler
Repair a small scheduler while preserving its command behavior and log order.
pub fn schedule(script: Vec<String>) -> Vec<String>
Jobs move between a pending queue and one running slot. Each job owns an ID
and payload, and its Drop implementation appends drop <id> to a shared
log. Keep Job non-Clone and preserve that destructor.
Commands and exact log order
Split each input line with split_whitespace. Commands are case-sensitive
and require exactly the listed tokens. IDs and payloads are single tokens;
there is no quoting syntax. Extra or missing tokens make a command invalid.
| Command | Behavior and log |
|---|---|
submit <id> <payload> |
Append a new job to pending; log submit <id>. |
start <id> |
Remove the first matching pending job. If another job is running, log preempt <oldid> and move it to the front of pending. Then log start <id> and install the selected job as running. |
finish |
Consume the running job, logging done <id>:<UPPERCASE-PAYLOAD>, followed immediately by drop <id>. If idle, log finish idle. |
cancel <id> |
Remove the first matching pending job, logging cancel <id> before its drop <id>. |
snapshot |
Log pending IDs in queue order as pending a,b,c, or pending - if empty. Leave the queue unchanged. |
A missing pending job produces start <id> missing or
cancel <id> missing without changing state. In particular, a failed start
does not preempt the running job, and cancel does not inspect the running slot.
Duplicate IDs are allowed. Searches choose the first matching pending job,
even if another job with that ID is running. Uppercasing uses Rust's
String::to_uppercase, including Unicode behavior.
Invalid commands log bad <line>, retaining the original line's whitespace.
At the end, log shutdown, drop the running job if present, then drop
pending jobs from front to back. An empty script returns ["shutdown"].
For example:
Commands:
submit a alpha
submit b beta
start a
start b
finish
Log:
submit a
submit b
start a
preempt a
start b
done b:BETA
drop b
shutdown
drop a
Start: read before moving
The starter assigns Some(job) to running, then tries to read
job.id. Moving the job makes that local binding unavailable, causing
E0382. Log its ID before the move, or access it through its new owner.
Moving a job does not invoke its destructor. That is why preemption returns
a job to the queue without a drop line.
Finish: preserve fields needed by Drop
Destructuring job to move out its strings causes E0509 because Job
implements Drop. Its destructor must receive a valid whole value.
Give Job a completion method that takes self. It can borrow the ID
and payload to construct the completion line, emit it, and let the job be
dropped when the method ends.
Implementing Drop does not forbid every field operation. With mutable
access, std::mem::take or replace can move a field out while leaving
a valid replacement. That is unnecessary for completing this job.
The supplied redundant-clone lint catches some unnecessary clones; it does
not enforce a universal ban on cloning. Keep the ownership-based design
requested here instead of adding Clone to Job. The supplied
Rc::clone shares the log handle, not the job.
Cancel: keep an index, not a borrowed job
The starter finds a reference inside the queue, removes an element, and then uses that reference. The overlapping immutable and mutable borrows cause E0502.
Use position to obtain an index. Once the search finishes, the index
does not keep the queue borrowed. Emit the cancellation line before
removing and dropping the job.
Snapshot: borrow IDs
Iteration yields &Job. Moving j.id out of that shared reference
causes E0507. Use j.id.as_str() to borrow each ID for joining.
This avoids cloning each ID, but constructing the reference vector and joined log string can still allocate. A borrowed ID does not make the whole snapshot operation allocation-free.
Check lifecycle behavior
The log exposes destructor calls, not every ownership move. Expected traces help detect early drops, missing completion messages, and shutdown ordering. They are evidence for the tested paths, not a general proof that values cannot leak or that destructors always run under every exit condition.
Keep the explicit shutdown loop so front-to-back destruction follows from the code. Do not rely on an assumed container destructor order.
A passing submission must compile, pass the tests, and pass
clippy -D warnings.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.