We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Smart Pointers and Interior Mutability step 5 of 26
Rc<T>: shared ownership by reference counting
Process acquire and release operations over shared vectors, then report their sums and remaining strong-reference counts.
pub fn share_report(defs: Vec<Vec<i64>>, refs: Vec<usize>) -> (Vec<i64>, Vec<usize>)
Wrap each input definition in its own Rc<Vec<i64>>, including definitions whose contents happen to be equal. Keep those original handles alive. Use a stack for additional handles acquired by the protocol.
Process one operation at a time
For every r in refs, apply the first matching rule:
| Condition | Action | Value to append |
|---|---|---|
| r == usize::MAX | release the most recently acquired handle, if any | -1 |
| r < defs.len() | acquire and retain another Rc handle to definition r | sum of that vector |
| otherwise | leave all held handles unchanged | -1 |
A release on an empty stack is allowed. An empty definition sums to zero. Tested sums fit in i64. A legitimate sum can equal -1, so an output value alone does not identify which kind of operation occurred.
Return the output values in operation order and one strong count per definition in definition order. Measure counts before dropping the remaining acquired handles. Each count is one original handle plus the number of acquired handles to that definition still on the stack.
The fixtures use a 64-bit runtime, where the release marker usize::MAX
is 18446744073709551615. Use the constant in Rust rather than a
hard-coded decimal. This numeric value is target-dependent.
Work through an example
With definitions [[5], [7]] and operations
[0, 1, 0, usize::MAX, 9]:
- The first three operations acquire handles for definitions 0, 1 and 0,
producing values
[5, 7, 5]. - The release removes the last handle, which refers to definition 0.
- The invalid index 9 changes nothing. Both final operations append -1.
Return ([5, 7, 5, -1, -1], [2, 2]). Each definition has its original
handle and one retained acquisition. With no operations, every count is
one. With no definitions, all operations produce -1 and the count vector
is empty.
Clone the handle, not the vector
Rc provides shared ownership within one thread. Rc::clone(&handle) creates another handle to the same value and increments its strong count. It does not clone the vector's elements. Cloning the Vec itself instead would create independent contents and would not increase this Rc count.
handle.clone() has the same behavior when handle is an Rc. The qualified Rc::clone spelling makes that choice explicit. The optional clone_on_ref_ptr lint prefers it, but is not enabled by default.
Dropping a strong handle decrements the count. The value is dropped when the last strong owner is released. Weak handles, if present, can retain the allocation's bookkeeping after the value is gone. This exercise creates no Weak handles.
Rc's reference counting is not atomic, and Rc is neither Send nor Sync. Arc supports atomic reference counting for cross-thread ownership when its contents satisfy the required bounds. That distinction is about access guarantees, not a fixed instruction count or universal speed ratio.
Repair the move in the starter
The starter tries to move a Vec out through an Rc dereference:
let owned: Vec<i64> = *defs[r];
This causes E0507. Dereferencing the Rc provides shared access; moving
out a non-Copy Vec could leave other handles without a valid value.
You only need to read it: defs[r].iter().sum() borrows its elements.
Directly calling defs[r].push(0) would also fail because Rc does not implement DerefMut. This does not mean mutation is impossible in every Rc design: get_mut supports unique access, and interior-mutability types support other access patterns. Neither is needed for this read-only task.
Release means dropping the returned handle
Vec::pop removes and returns an Option<Rc<_>>. It does not by itself destroy a handle that you keep in a local variable. In this protocol, discard or explicitly drop that result so the strong count decreases before the final measurement.
Check the release marker before treating an out-of-range index as invalid. Otherwise release would append the right value but leave ownership counts wrong. Keep repeated acquisitions: every successful acquisition adds one handle, even if the top of the stack already refers to that definition.
The submission must compile, match values and counts, and pass Clippy with warnings denied.
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.