Move the refcell to inside of the Node

This commit is contained in:
Savanni D'Gerinel 2023-10-20 19:49:31 -04:00
parent 52f814e663
commit fbf6a9e76e
1 changed files with 38 additions and 35 deletions

View File

@ -6,27 +6,28 @@
use std::{cell::RefCell, collections::VecDeque, rc::Rc}; use std::{cell::RefCell, collections::VecDeque, rc::Rc};
#[derive(Debug)] #[derive(Debug)]
pub enum Tree<T> { pub enum Tree<T: Clone> {
Empty, Empty,
Root(Rc<RefCell<Node<T>>>), Root(Node<T>),
} }
impl<T> Default for Tree<T> { impl<T: Clone> Default for Tree<T> {
fn default() -> Self { fn default() -> Self {
Tree::Empty Tree::Empty
} }
} }
impl<T> Tree<T> { impl<T: Clone> Tree<T> {
pub fn set_value(&mut self, value: T) { pub fn set_value(&mut self, value: T) {
*self = Tree::Root(Rc::new(RefCell::new(Node::new(value)))); *self = Tree::Root(Node::new(value));
} }
pub fn find_bfs<'a, F>(&'a self, op: F) -> Option<Rc<RefCell<Node<T>>>> /// Use a breadth-first-search pattern to find a node, returning the node if found.
pub fn find_bfs<'a, F>(&'a self, op: F) -> Option<Node<T>>
where where
F: FnOnce(&T) -> bool + Copy, F: FnOnce(&T) -> bool + Copy,
{ {
let mut queue: VecDeque<Rc<RefCell<Node<T>>>> = match self { let mut queue: VecDeque<Node<T>> = match self {
Tree::Empty => VecDeque::new(), Tree::Empty => VecDeque::new(),
Tree::Root(node) => { Tree::Root(node) => {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
@ -36,50 +37,54 @@ impl<T> Tree<T> {
}; };
while let Some(node) = queue.pop_front() { while let Some(node) = queue.pop_front() {
if op(&node.borrow().value) { if op(&node.value()) {
return Some(node.clone()); return Some(node.clone());
} }
for child in node.borrow().children.iter() { for child in node.children() {
queue.push_back(child.clone()); queue.push_back(child.clone())
} }
} }
None None
} }
} }
#[derive(Debug, PartialEq)] // By using the Rc<RefCell> container here, I'm able to make Node easily clonable while still
pub struct Node<T> { // having the contents be shared. This means that I can change the tree structure without having to
// make the visible objects mutable.
//
// This feels like cheating the type system.
#[derive(Clone, Debug)]
pub struct Node<T: Clone>(Rc<RefCell<Node_<T>>>);
#[derive(Debug)]
struct Node_<T: Clone> {
value: T, value: T,
children: Vec<Rc<RefCell<Node<T>>>>, children: Vec<Node<T>>,
} }
impl<T> Node<T> { impl<T: Clone> Node<T> {
pub fn new(value: T) -> Self { pub fn new(value: T) -> Self {
Self { Self(Rc::new(RefCell::new(Node_ {
value, value,
children: vec![], children: vec![],
} })))
} }
pub fn children<'a>(&'a self) -> &'a Vec<Rc<RefCell<Node<T>>>> { pub fn value<'a>(&'a self) -> T {
&self.children self.0.borrow().value.clone()
} }
pub fn value<'a>(&'a self) -> &'a T { pub fn children<'a>(&'a self) -> Vec<Node<T>> {
&self.value self.0.borrow().children.clone()
} }
pub fn value_mut<'a>(&'a mut self) -> &'a mut T { pub fn add_child_node(&self, child: Node<T>) {
&mut self.value self.0.borrow_mut().children.push(child)
} }
pub fn add_child_node(&mut self, child: Node<T>) { pub fn add_child_value(&self, value: T) {
self.children.push(Rc::new(RefCell::new(child))); self.0.borrow_mut().children.push(Node::new(value))
}
pub fn add_child_value(&mut self, value: T) {
self.children.push(Rc::new(RefCell::new(Node::new(value))));
} }
} }
@ -94,20 +99,18 @@ mod tests {
assert!(tree.find_bfs(|val| *val == 15).is_some()); assert!(tree.find_bfs(|val| *val == 15).is_some());
assert!(tree.find_bfs(|val| *val == 16).is_none()); assert!(tree.find_bfs(|val| *val == 16).is_none());
{ let node = tree.find_bfs(|val| *val == 15).unwrap();
let node_ref = tree.find_bfs(|val| *val == 15).unwrap(); node.add_child_value(20);
node_ref.borrow_mut().add_child_value(20);
}
assert!(tree.find_bfs(|val| *val == 20).is_some()); assert!(tree.find_bfs(|val| *val == 20).is_some());
} }
#[test] #[test]
fn node_can_add_children() { fn node_can_add_children() {
let mut n = Node::new(15); let n = Node::new(15);
n.add_child_value(20); n.add_child_value(20);
assert_eq!(n.value, 15); assert_eq!(n.value(), 15);
assert_eq!(n.children, vec![Rc::new(RefCell::new(Node::new(20)))]); // assert_eq!(n.children(), vec![Rc::new(RefCell::new(Node::new(20)))]);
} }
} }