We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Smart Pointers and Interior Mutability step 15 of 26
Rc<RefCell<T>>: shared inboxes and an arena alternative
Implement the same event bus with two ownership designs:
pub fn event_bus(subscribers: Vec<String>, events: Vec<String>) -> Vec<(String, Vec<String>)>
pub fn event_bus_arena(subscribers: Vec<String>, events: Vec<String>) -> Vec<(String, Vec<String>)>
Both functions must produce identical results. Each distinct subscriber name has one inbox. Each occurrence of that name registers a route to the inbox, so duplicate registrations cause duplicate deliveries.
Event format and output
Split each event at its first ASCII space. Everything before it is the topic; everything after it is the message. Preserve the remaining text exactly, including extra spaces and tabs. Without a space, the whole event is the topic and the message is empty. Do not trim either part.
A topic equal to * delivers to every route. Otherwise, deliver only
to routes whose names exactly match the topic. Unmatched events do
nothing. Process events in input order and routes in registration order.
Return one (name, messages) row per distinct subscriber name, sorted
by Rust's ordinary String ordering. Keep messages in delivery order.
Include subscribers with empty inboxes. No subscribers means no rows;
no events means every registered inbox is empty.
For subscribers ["alerts", "alerts", "logs"] and events
["alerts fire", "* ready"], return:
alerts: ["fire", "fire", "ready", "ready"]
logs: ["ready"]
The wildcard is a topic rule, not a subscription pattern. A subscriber
named * does not receive every targeted event. Names containing spaces
cannot match a single parsed topic, but still receive wildcard events.
An empty topic can match an empty subscriber name.
First version: shared inbox handles
Use Rc<RefCell<Vec<String>>> for each inbox. Rc lets the map of
distinct inboxes and the route list retain handles to the same allocation.
RefCell provides mutable access through runtime borrow checks.
Keep a BTreeMap from names to inbox handles and a separate route vector with one entry per registration. Clone the Rc handle when adding a route; do not clone the inbox's Vec. For delivery, borrow the inbox mutably, append the message, and release that borrow before the next delivery.
A mutable RefCell borrow conflicts with any other live borrow of the same cell. borrow_mut panics on a conflict; try_borrow_mut returns an error instead. Keep guards short, especially before calling code that might access the same cell again. This exercise has no callbacks.
Rc<RefCell<T>> and RefCell<Rc<T>> provide different access. The first shares a mutable cell. The second permits replacing the Rc handle in a cell; it does not itself provide mutable access to the Rc's contents.
Why the starter uses the wrong shared pointer
The starter's Arc<RefCell<Vec<String>>> compiles as a single-threaded value, but Clippy's arc_with_non_send_sync lint rejects its construction under this site's warnings-as-errors policy. Replace Arc with Rc here.
Arc makes reference counting atomic; it does not make its contents safe for concurrent access. RefCell<T> is Send when T is Send, but is not Sync. Thus this Arc type cannot provide shared inbox access across threads. A threaded design would need a suitable synchronization strategy, such as a mutex, and is outside this exercise.
Second version: one owner and indexed routes
Implement event_bus_arena without Rc or RefCell. Store inboxes in
Vec<Vec<String>>, names in a parallel vector, and routes as usize
indices. Repeated names reuse the same index. A name-to-index map can
find or create the slot during registration.
Keep these vectors aligned and do not remove or reorder their slots during delivery. At the end, pair each name with its inbox and sort the rows by name. The first version already gets that order from its BTreeMap.
This design uses exclusive access to centrally owned storage instead of runtime borrow checks. It still requires valid indices and can panic if those invariants are broken. The outer Vec stores the inbox Vec headers together; their message buffers are separate allocations.
Shared handles are useful when an inbox must remain alive independently of the bus. Indices are useful when one owner can manage all storage and its lifetime. Neither design is universally faster or simpler; choose based on those ownership needs.
Neither implementation here builds an ownership cycle. In a larger graph, strong Rc cycles can retain values, and recursively formatting a cyclic structure can exhaust the stack. Use weak back-references where appropriate and a bounded or cycle-aware representation when inspecting such graphs.
Complete both functions. The submission must compile, match the ordered inbox contents 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.