Skip to content

Instantly share code, notes, and snippets.

@stevehobbsdev
Created October 22, 2025 13:29
Show Gist options
  • Select an option

  • Save stevehobbsdev/63c1b9ac2190f0d2dde700bb2bb50b2a to your computer and use it in GitHub Desktop.

Select an option

Save stevehobbsdev/63c1b9ac2190f0d2dde700bb2bb50b2a to your computer and use it in GitHub Desktop.
Graph implementation to practise some Rust
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