Skip to content

Instantly share code, notes, and snippets.

@ssrlive
Last active June 16, 2023 01:42
Show Gist options
  • Save ssrlive/f515fac13a08b860b9b59a3071e17013 to your computer and use it in GitHub Desktop.
Save ssrlive/f515fac13a08b860b9b59a3071e17013 to your computer and use it in GitHub Desktop.
Demo of a Group/Node tree system in rust.
/*
[dependencies]
as-any = "0.3"
erased-serde = "0.3"
rustfmt = "0.10"
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1" }
uuid = { version = "1.2", features = ["v4", "serde"] }
*/
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
use uuid::Uuid;
pub trait Node: as_any::AsAny + std::fmt::Debug + erased_serde::Serialize {
fn get_uuid(&self) -> &Uuid;
fn get_title(&self) -> Option<&str>;
}
erased_serde::serialize_trait_object!(Node);
#[derive(Clone, Debug, Default, serde::Serialize)]
pub struct Group {
uuid: Uuid,
name: String,
children: Vec<Rc<RefCell<dyn Node>>>,
}
impl PartialEq for Group {
fn eq(&self, other: &Self) -> bool {
self.uuid == other.uuid && self.compare_children(other)
}
}
impl Eq for Group {}
impl Group {
pub fn new(name: &str) -> Self {
Self {
uuid: Uuid::new_v4(),
name: name.to_string(),
..Group::default()
}
}
pub fn add_child(&mut self, child: Rc<RefCell<dyn Node>>) {
self.children.push(child);
}
pub fn get_children(&self) -> &Vec<Rc<RefCell<dyn Node>>> {
&self.children
}
pub fn get_children_mut(&mut self) -> &mut Vec<Rc<RefCell<dyn Node>>> {
&mut self.children
}
pub fn set_name(&mut self, name: &str) {
self.name = name.to_string();
}
fn compare_children(&self, other: &Self) -> bool {
if self.children.len() != other.children.len() {
return false;
}
self.children
.iter()
.zip(other.children.iter())
.all(|(a, b)| {
if let (Some(a), Some(b)) = (
a.borrow().as_any().downcast_ref::<Group>(),
b.borrow().as_any().downcast_ref::<Group>(),
) {
a == b
} else if let (Some(a), Some(b)) = (
a.borrow().as_any().downcast_ref::<Entry>(),
b.borrow().as_any().downcast_ref::<Entry>(),
) {
a == b
} else {
false
}
})
}
}
impl Node for Group {
fn get_uuid(&self) -> &Uuid {
&self.uuid
}
fn get_title(&self) -> Option<&str> {
Some(&self.name)
}
}
pub struct NodeIterator {
queue: VecDeque<Rc<RefCell<dyn Node>>>,
}
impl NodeIterator {
pub fn create(root: Rc<RefCell<dyn Node>>) -> Self {
let mut queue = VecDeque::new();
queue.push_back(root);
Self { queue }
}
}
impl Iterator for NodeIterator {
type Item = Rc<RefCell<dyn Node>>;
fn next(&mut self) -> Option<Self::Item> {
let node = self.queue.pop_front()?;
if let Some(group) = node.borrow().as_any().downcast_ref::<Group>() {
self.queue.extend(group.get_children().iter().cloned());
}
Some(node)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize)]
pub struct Entry {
uuid: Uuid,
title: Option<String>,
}
impl Entry {
pub fn new() -> Self {
Self {
uuid: Uuid::new_v4(),
..Entry::default()
}
}
pub fn set_title(&mut self, title: Option<&str>) {
self.title = title.map(|s| s.to_string());
}
}
impl Node for Entry {
fn get_uuid(&self) -> &Uuid {
&self.uuid
}
fn get_title(&self) -> Option<&str> {
self.title.as_deref()
}
}
fn main() {
let mut group = Group::new("Group root");
group.add_child(Rc::new(RefCell::new(Entry::new())));
group.add_child(Rc::new(RefCell::new(Group::new("Group 1"))));
let mut entry = Entry::new();
entry.set_title(Some("Entry 2"));
group.add_child(Rc::new(RefCell::new(entry)));
// clone the group
let cloned_group = group.clone();
assert_eq!(group, cloned_group);
for child in group.get_children_mut() {
let mut child = child.borrow_mut();
if let Some(e) = child.as_any_mut().downcast_mut::<Entry>() {
println!("{:?}", e);
e.set_title(Some("Entry 2 updated"));
} else if let Some(g) = child.as_any_mut().downcast_mut::<Group>() {
println!("{:?}", g);
g.set_name("Group 1 updated");
}
}
for child in group.get_children() {
if let Some(e) = child.borrow().as_any().downcast_ref::<Entry>() {
println!("==> {:?}", e);
} else if let Some(g) = child.borrow().as_any().downcast_ref::<Group>() {
println!("==> {:?}", g);
}
}
// println!("group: {:?}", group);
let string = serde_json::to_string(&group).unwrap();
println!("string: \n\n{}\n", string);
println!("=========================================");
let root: Rc<RefCell<dyn Node>> = Rc::new(RefCell::new(group));
NodeIterator::create(root).for_each(|node| {
if let Some(group) = node.borrow_mut().as_any_mut().downcast_mut::<Group>() {
group.set_name("Group xxxxx updated");
}
println!("node: {:?}", node.borrow().get_title());
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment