Learn Rust With Entirely Too Many Linked Lists
22

Building

push_front: allocate a node, link it to the old head in both directions, swing self.head. The shape is the same as the singly-linked stack but every field write goes through borrow_mut() on a RefCell, and every node pointer is cloned through Rc::clone.

  1. Build the new node, wrap it in Rc::new(RefCell::new(...)), then patch up the old head's prev pointer to point at the new node. The old head and the new node both hold an Rc to each other — refcount 2 on each.
    pub fn push_front(&mut self, elem: T) {
        let new_head = Rc::new(RefCell::new(Node {
            elem,
            prev: None,
            next: None,
        }));
        match self.head.take() {
            Some(old_head) => {
                old_head.borrow_mut().prev = Some(new_head.clone());
                new_head.borrow_mut().next = Some(old_head);
                self.head = Some(new_head);
            }
            None => {
                // empty list: head and tail both become the new node
                self.tail = Some(new_head.clone());
                self.head = Some(new_head);
            }
        }
    }
  2. borrow_mut() returns a RefMut<T> guard. While the guard is alive, no other borrow of that RefCell can exist; another borrow() or borrow_mut() on the same cell will panic. The compiler does not know any of this — the check is at runtime, on every call.
    // fine: two separate cells
    let a = node_a.borrow_mut();
    let b = node_b.borrow_mut();
    
    // panic: same cell, two mut borrows
    let x = node.borrow_mut();
    let y = node.borrow_mut(); // thread 'main' panicked at 'already borrowed: BorrowMutError'
  3. The empty-list arm has to set both head and tail to the same node, which means cloning the Rc. Rc::clone (also spelled .clone() on an Rc) bumps the refcount, doesn't deep-copy the node. Two Rc handles, one heap allocation.
    // after push_front on an empty list:
    // self.head -> Rc(count=2) -> Node{...}
    // self.tail -> Rc(count=2) -> (same Node)