Created
October 22, 2025 13:29
-
-
Save stevehobbsdev/63c1b9ac2190f0d2dde700bb2bb50b2a to your computer and use it in GitHub Desktop.
Graph implementation to practise some Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::cell::RefCell; | |
| use std::{collections::VecDeque, rc::Rc}; | |
| type NodeContainer = Rc<RefCell<Node>>; | |
| #[derive(Debug, Clone)] | |
| enum Object { | |
| User(String), | |
| Folder(String), | |
| Document(String), | |
| } | |
| fn folder(name: &str) -> Object { | |
| Object::Folder(name.to_string()) | |
| } | |
| fn doc(name: &str) -> Object { | |
| Object::Document(name.to_string()) | |
| } | |
| fn user(name: &str) -> Object { | |
| Object::User(name.to_string()) | |
| } | |
| impl PartialEq for Object { | |
| fn eq(&self, other: &Self) -> bool { | |
| match (self, other) { | |
| (Object::User(a), Object::User(b)) => a == b, | |
| (Object::Document(a), Object::Document(b)) => a == b, | |
| (Object::Folder(a), Object::Folder(b)) => a == b, | |
| _ => false, | |
| } | |
| } | |
| } | |
| #[derive(Debug)] | |
| struct Node { | |
| value: Object, | |
| nodes: Vec<NodeContainer>, | |
| } | |
| impl Node { | |
| pub fn new(value: Object, nodes: Vec<NodeContainer>) -> NodeContainer { | |
| Rc::new(RefCell::new(Node { value, nodes })) | |
| } | |
| pub fn leaf(value: Object) -> NodeContainer { | |
| Rc::new(RefCell::new(Node { | |
| value, | |
| nodes: vec![], | |
| })) | |
| } | |
| pub fn with_child(value: Object, child: NodeContainer) -> NodeContainer { | |
| Rc::new(RefCell::new(Node { | |
| value, | |
| nodes: vec![child], | |
| })) | |
| } | |
| pub fn add_child(this: &NodeContainer, new_child: NodeContainer) { | |
| this.borrow_mut().nodes.push(new_child) | |
| } | |
| pub fn remove_child(this: &NodeContainer, child: NodeContainer) { | |
| let mut node = this.borrow_mut(); | |
| node.nodes.retain(|c| !Rc::ptr_eq(c, &child)); | |
| } | |
| pub fn are_related(node: &NodeContainer, o: &Object) -> bool { | |
| Node::dfs(o, node).is_some() | |
| } | |
| pub fn dfs(value: &Object, node: &NodeContainer) -> Option<NodeContainer> { | |
| if node.borrow().value == *value { | |
| return Some(Rc::clone(node)); | |
| } | |
| for n in node.borrow().nodes.iter() { | |
| if let Some(found) = Node::dfs(value, n) { | |
| return Some(found); | |
| } | |
| } | |
| None | |
| } | |
| pub fn bfs(value: &Object, node: &NodeContainer) -> Option<NodeContainer> { | |
| let mut queue = VecDeque::new(); | |
| queue.push_back(Rc::clone(node)); | |
| while let Some(this_node) = queue.pop_front() { | |
| if this_node.borrow().value == *value { | |
| return Some(this_node); | |
| } | |
| for child in this_node.borrow().nodes.iter() { | |
| queue.push_back(Rc::clone(child)); | |
| } | |
| } | |
| None | |
| } | |
| } | |
| pub fn run() { | |
| let o = doc("year-end.docx"); | |
| let doc1 = Node::leaf(o.clone()); | |
| let user1 = Node::leaf(user("steve")); | |
| let folder1 = Node::leaf(folder("finances")); | |
| Node::add_child(&folder1, doc1); | |
| Node::add_child(&user1, folder1); | |
| println!("{:?}", user1); | |
| println!("{:?}", Node::are_related(&user1, &doc("year-end.docx"))); // true | |
| println!("{:?}", Node::are_related(&user1, &doc("salaries.docx"))); // false | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| #[test] | |
| fn can_create_node() { | |
| let user1 = Node::leaf(user("Dom Jolly")); | |
| assert_eq!(user1.borrow().value, Object::User("Dom Jolly".to_owned())); | |
| } | |
| #[test] | |
| fn nodes_are_shared_refs() { | |
| let folder = Node::leaf(folder("folder_1")); | |
| let user = Node::with_child(user("Dom Jolly"), folder.clone()); | |
| assert!(Rc::ptr_eq(&user.borrow().nodes[0], &folder)); | |
| } | |
| #[test] | |
| fn can_find_child() { | |
| let folder1 = Node::leaf(folder("folder_1")); | |
| let user = Node::with_child(user("Dom Jolly"), folder1); | |
| assert_eq!(true, Node::are_related(&user, &folder("folder_1"))); | |
| } | |
| #[test] | |
| fn can_find_nested_child() { | |
| let document1 = Node::leaf(doc("document1")); | |
| let folder1 = Node::with_child(folder("folder_1"), document1); | |
| let user = Node::with_child(user("Dom Jolly"), folder1); | |
| assert_eq!(true, Node::are_related(&user, &doc("document1"))); | |
| } | |
| #[test] | |
| fn are_not_related() { | |
| let document1 = Node::leaf(doc("document1")); | |
| let folder1 = Node::with_child(folder("folder_1"), document1); | |
| let user = Node::with_child(user("Dom Jolly"), folder1); | |
| assert_eq!(false, Node::are_related(&user, &doc("document2"))); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment