Last active
June 16, 2023 01:42
-
-
Save ssrlive/f515fac13a08b860b9b59a3071e17013 to your computer and use it in GitHub Desktop.
Demo of a Group/Node tree system in 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
| /* | |
| [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