diff --git a/Cargo.lock b/Cargo.lock index aa82149..72c8928 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4060,6 +4060,10 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +[[package]] +name = "tree" +version = "0.1.0" + [[package]] name = "try-lock" version = "0.2.4" diff --git a/Cargo.toml b/Cargo.toml index 266bdc5..80b71cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,5 @@ members = [ "result-extended", "screenplay", "sgf", + "tree", ] diff --git a/build.sh b/build.sh index 4168a1a..dcaed56 100755 --- a/build.sh +++ b/build.sh @@ -23,6 +23,7 @@ RUST_ALL_TARGETS=( "result-extended" "screenplay" "sgf" + "tree" ) build_rust_targets() { diff --git a/tree/Cargo.toml b/tree/Cargo.toml new file mode 100644 index 0000000..7ee0dbe --- /dev/null +++ b/tree/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "tree" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/tree/src/lib.rs b/tree/src/lib.rs new file mode 100644 index 0000000..77088b0 --- /dev/null +++ b/tree/src/lib.rs @@ -0,0 +1,113 @@ +//! This data structure is a generic tree which can contain any data. That data itself need to keep +//! track of its own tree structure. +//! +//! This surely already exists. I am created it to test my own ability to do things in Rust. + +use std::{cell::RefCell, collections::VecDeque, rc::Rc}; + +#[derive(Debug)] +pub enum Tree { + Empty, + Root(Rc>>), +} + +impl Default for Tree { + fn default() -> Self { + Tree::Empty + } +} + +impl Tree { + pub fn set_value(&mut self, value: T) { + *self = Tree::Root(Rc::new(RefCell::new(Node::new(value)))); + } + + pub fn find_bfs<'a, F>(&'a self, op: F) -> Option>>> + where + F: FnOnce(&T) -> bool + Copy, + { + let mut queue: VecDeque>>> = match self { + Tree::Empty => VecDeque::new(), + Tree::Root(node) => { + let mut queue = VecDeque::new(); + queue.push_back(node.clone()); + queue + } + }; + + while let Some(node) = queue.pop_front() { + if op(&node.borrow().value) { + return Some(node.clone()); + } + + for child in node.borrow().children.iter() { + queue.push_back(child.clone()); + } + } + None + } +} + +#[derive(Debug, PartialEq)] +pub struct Node { + value: T, + children: Vec>>>, +} + +impl Node { + pub fn new(value: T) -> Self { + Self { + value, + children: vec![], + } + } + + pub fn children<'a>(&'a self) -> &'a Vec>>> { + &self.children + } + + pub fn value<'a>(&'a self) -> &'a T { + &self.value + } + + pub fn value_mut<'a>(&'a mut self) -> &'a mut T { + &mut self.value + } + + pub fn add_child_node(&mut self, child: Node) { + self.children.push(Rc::new(RefCell::new(child))); + } + + pub fn add_child_value(&mut self, value: T) { + self.children.push(Rc::new(RefCell::new(Node::new(value)))); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_find_node_in_tree() { + let mut tree = Tree::default(); + tree.set_value(15); + assert!(tree.find_bfs(|val| *val == 15).is_some()); + assert!(tree.find_bfs(|val| *val == 16).is_none()); + + { + let node_ref = tree.find_bfs(|val| *val == 15).unwrap(); + node_ref.borrow_mut().add_child_value(20); + } + + assert!(tree.find_bfs(|val| *val == 20).is_some()); + } + + #[test] + fn node_can_add_children() { + let mut n = Node::new(15); + n.add_child_value(20); + + assert_eq!(n.value, 15); + assert_eq!(n.children, vec![Rc::new(RefCell::new(Node::new(20)))]); + } +}