From 8956fab9bbe66e8aa05f618c29fbb49487ce9646 Mon Sep 17 00:00:00 2001
From: "Dustin J. Mitchell" <djmitche@google.com>
Date: Fri, 11 Aug 2023 08:39:30 -0400
Subject: [PATCH] Put Ref/Cell on its own slide (#1062)

---
 src/SUMMARY.md  |  1 +
 src/std/cell.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/std/rc.md   | 44 ++++++-----------------------------------
 3 files changed, 59 insertions(+), 38 deletions(-)
 create mode 100644 src/std/cell.md

diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 5e17fa1a..218f69df 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -113,6 +113,7 @@
     - [Recursive Data Types](std/box-recursive.md)
     - [Niche Optimization](std/box-niche.md)
   - [Rc](std/rc.md)
+  - [Cell/RefCell](std/cell.md)
 - [Modules](modules.md)
   - [Visibility](modules/visibility.md)
   - [Paths](modules/paths.md)
diff --git a/src/std/cell.md b/src/std/cell.md
new file mode 100644
index 00000000..0b2f4a4c
--- /dev/null
+++ b/src/std/cell.md
@@ -0,0 +1,52 @@
+# `Cell` and `RefCell`
+
+[`Cell`][https://doc.rust-lang.org/std/cell/struct.Cell.html] and
+[`RefCell`](https://doc.rust-lang.org/std/cell/struct.RefCell.html) implement
+what Rust calls *interior mutability:* mutation of values in an immutable
+context.
+
+`Cell` is typically used for simple types, as it requires copying or moving
+values. More complex interior types typically use `RefCell`, which tracks shared
+and exclusive references at runtime and panics if they are misused.
+
+```rust,editable
+use std::cell::RefCell;
+use std::rc::Rc;
+
+#[derive(Debug, Default)]
+struct Node {
+    value: i64,
+    children: Vec<Rc<RefCell<Node>>>,
+}
+
+impl Node {
+    fn new(value: i64) -> Rc<RefCell<Node>> {
+        Rc::new(RefCell::new(Node { value, ..Node::default() }))
+    }
+
+    fn sum(&self) -> i64 {
+        self.value + self.children.iter().map(|c| c.borrow().sum()).sum::<i64>()
+    }
+}
+
+fn main() {
+    let root = Node::new(1);
+    root.borrow_mut().children.push(Node::new(5));
+    let subtree = Node::new(10);
+    subtree.borrow_mut().children.push(Node::new(11));
+    subtree.borrow_mut().children.push(Node::new(12));
+    root.borrow_mut().children.push(subtree);
+
+    println!("graph: {root:#?}");
+    println!("graph sum: {}", root.borrow().sum());
+}
+```
+
+<details>
+
+* If we were using `Cell` instead of `RefCell` in this example, we would have to move the `Node` out of the `Rc` to push children, then move it back in. This is safe because there's always one, un-referenced value in the cell, but it's not ergonomic.
+* To do anything with a Node, you must call a `RefCell` method, usually `borrow` or `borrow_mut`.
+* Demonstrate that reference loops can be created by adding `root` to `subtree.children` (don't try to print it!).
+* To demonstrate a runtime panic, add a `fn inc(&mut self)` that increments `self.value` and calls the same method on its children. This will panic in the presence of the reference loop, with `thread 'main' panicked at 'already borrowed: BorrowMutError'`.
+
+</details>
diff --git a/src/std/rc.md b/src/std/rc.md
index 18ec5bcc..73e887e3 100644
--- a/src/std/rc.md
+++ b/src/std/rc.md
@@ -15,17 +15,14 @@ fn main() {
 }
 ```
 
-* If you need to mutate the data inside an `Rc`, you will need to wrap the data in
-  a type such as [`Cell` or `RefCell`][2].
-* See [`Arc`][3] and [`Mutex`][4] if you are in a multi-threaded context.
-* You can *downgrade* a shared pointer into a [`Weak`][5] pointer to create cycles
+* See [`Arc`][2] and [`Mutex`][3] if you are in a multi-threaded context.
+* You can *downgrade* a shared pointer into a [`Weak`][4] pointer to create cycles
   that will get dropped.
 
 [1]: https://doc.rust-lang.org/std/rc/struct.Rc.html
-[2]: https://doc.rust-lang.org/std/cell/index.html
-[3]: ../concurrency/shared_state/arc.md
-[4]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
-[5]: https://doc.rust-lang.org/std/rc/struct.Weak.html
+[2]: ../concurrency/shared_state/arc.md
+[3]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
+[4]: https://doc.rust-lang.org/std/rc/struct.Weak.html
 
 <details>
 
@@ -34,37 +31,8 @@ fn main() {
 * `Rc::clone` is cheap: it creates a pointer to the same allocation and increases the reference count. Does not make a deep clone and can generally be ignored when looking for performance issues in code.
 * `make_mut` actually clones the inner value if necessary ("clone-on-write") and returns a mutable reference.
 * Use `Rc::strong_count` to check the reference count.
-* Compare the different datatypes mentioned. `Box` enables (im)mutable borrows that are enforced at compile time. `RefCell` enables (im)mutable borrows that are enforced at run time and will panic if it fails at runtime.
 * `Rc::downgrade` gives you a *weakly reference-counted* object to
   create cycles that will be dropped properly (likely in combination with
-  `RefCell`).
-
-```rust,editable
-use std::rc::{Rc, Weak};
-use std::cell::RefCell;
-
-#[derive(Debug)]
-struct Node {
-    value: i64,
-    parent: Option<Weak<RefCell<Node>>>,
-    children: Vec<Rc<RefCell<Node>>>,
-}
-
-fn main() {
-    let mut root = Rc::new(RefCell::new(Node {
-        value: 42,
-        parent: None,
-        children: vec![],
-    }));
-    let child = Rc::new(RefCell::new(Node {
-        value: 43,
-        children: vec![],
-        parent: Some(Rc::downgrade(&root))
-    }));
-    root.borrow_mut().children.push(child);
-
-    println!("graph: {root:#?}");
-}
-```
+  `RefCell`, on the next slide).
 
 </details>