commit 629075f94d07cd22cd98e5cc7036b563486a7e17 Author: Aode (Lion) Date: Thu Feb 10 14:44:58 2022 -0600 It's a tree diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..15c48ea --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "a-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/examples/generate.rs b/examples/generate.rs new file mode 100644 index 0000000..800bf07 --- /dev/null +++ b/examples/generate.rs @@ -0,0 +1,63 @@ +use a_tree::Tree; + +#[derive(Debug, PartialEq, Eq, Hash)] +enum Direction { + Up, + Down, + Left, + Right, +} + +#[derive(Debug, Default)] +struct Coordinates { + x: usize, + y: usize, +} + +const ALL_DIRECTIONS: [Direction; 4] = [ + Direction::Up, + Direction::Down, + Direction::Left, + Direction::Right, +]; + +fn next_level(value: &Coordinates) -> Vec<(Direction, Coordinates)> { + ALL_DIRECTIONS + .into_iter() + .filter_map(|direction| { + let new_coords = match direction { + Direction::Up => Coordinates { + x: value.x, + y: value.y + 1, + }, + Direction::Right => Coordinates { + x: value.x + 1, + y: value.y, + }, + Direction::Down if value.y > 0 => Coordinates { + x: value.x, + y: value.y - 1, + }, + Direction::Left if value.x > 0 => Coordinates { + x: value.x - 1, + y: value.y, + }, + _ => return None, + }; + + Some((direction, new_coords)) + }) + .collect() +} + +fn main() { + let mut tree = Tree::generations(Coordinates::default(), 3, next_level); + + println!("{:#?}", tree); + println!("{:?}", tree.leaves()); + + tree.retain(|item| item.x > 0 && item.y > 0); + + println!("{:#?}", tree); + println!("{:?}", tree.leaves()); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4ae99f0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; +use std::hash::Hash; + +#[derive(Debug)] +pub struct Tree { + value: T, + children: HashMap>, +} + +impl Tree +where + K: Eq + Hash, +{ + pub fn new(item: T) -> Self { + Tree { + value: item, + children: HashMap::new(), + } + } + + pub fn generations(start: T, depth: usize, callback: F) -> Self + where + F: Fn(&T) -> Vec<(K, T)> + Copy, + { + let mut children = HashMap::new(); + + if depth != 0 { + for (key, value) in (callback)(&start) { + let child = Self::generations(value, depth - 1, callback); + children.insert(key, child); + } + } + + Tree { + value: start, + children, + } + } + + pub fn leaves(&self) -> Vec<(Vec<&K>, &T)> { + self.do_leaves(vec![]) + } + + fn do_leaves<'a>(&'a self, path: Vec<&'a K>) -> Vec<(Vec<&'a K>, &'a T)> { + if self.children.is_empty() { + vec![(path, &self.value)] + } else { + self.children + .iter() + .flat_map(|(key, child)| { + let mut path = path.clone(); + path.push(key); + child.do_leaves(path) + }) + .collect() + } + } + + pub fn retain(&mut self, callback: C) + where + C: Fn(&T) -> bool + Copy, + { + self.children.retain(|_key, child| { + child.retain(callback); + + if child.children.is_empty() { + (callback)(&child.value) + } else { + true + } + }); + } +} + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } +}