mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-08 22:28:12 -05:00
script/research/dark-forest: document everything
This commit is contained in:
@@ -21,22 +21,41 @@ use std::{collections::VecDeque, iter::FusedIterator, mem};
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
/// This struct represents a Leaf of a [`DarkTree`],
|
||||
/// holding this tree node data, along with positional
|
||||
/// indexes information, based on tree's traversal order.
|
||||
/// These indexes are only here to enable referencing
|
||||
/// connected nodes, and are *not* used as pointers by the
|
||||
/// tree. Creator must ensure they are properly setup.
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct DarkLeaf<T> {
|
||||
/// Data holded by this leaf
|
||||
data: T,
|
||||
/// Index showcasing this leaf's position, when all
|
||||
/// leafs are in order.
|
||||
index: usize,
|
||||
/// Index showcasing this leaf's parent tree, when all
|
||||
/// leafs are in order. None indicates this leaf has no
|
||||
/// parent.
|
||||
/// leafs are in order. None indicates that this leaf
|
||||
/// has no parent.
|
||||
parent_index: Option<usize>,
|
||||
/// Vector of indexes showcasing this leaf's children
|
||||
/// positions, when all leafs are in order. If vector
|
||||
/// is empty, it indicates that this leaf has no children.
|
||||
children_indexes: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<T> DarkLeaf<T> {
|
||||
/// Every leaf is initiated using default indexes.
|
||||
fn new(data: T) -> DarkLeaf<T> {
|
||||
Self { data, parent_index: None }
|
||||
Self { data, index: 0, parent_index: None, children_indexes: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct represents a Tree using DFS post-order traversal,
|
||||
/// where when we iterate through the tree, we first process tree
|
||||
/// node's children, and then the node itself, recursively.
|
||||
/// Based on this, initial tree node (leaf), known as the root,
|
||||
/// will always show up at the end of iteration.
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct DarkTree<T> {
|
||||
/// This tree's leaf information, along with its data
|
||||
@@ -46,20 +65,28 @@ struct DarkTree<T> {
|
||||
}
|
||||
|
||||
impl<T> DarkTree<T> {
|
||||
/// Initialize a [`DarkTree`], using provided data to
|
||||
/// generate its root.
|
||||
fn new(data: T, children: Vec<DarkTree<T>>) -> DarkTree<T> {
|
||||
let leaf = DarkLeaf::new(data);
|
||||
Self { leaf, children }
|
||||
}
|
||||
|
||||
/// Immutably iterate through the tree, using DFS post-order
|
||||
/// traversal.
|
||||
fn iter(&self) -> DarkTreeIter<'_, T> {
|
||||
DarkTreeIter { children: std::slice::from_ref(self), parent: None }
|
||||
}
|
||||
|
||||
/// Mutably iterate through the tree, using DFS post-order
|
||||
/// traversal.
|
||||
fn iter_mut(&mut self) -> DarkTreeIterMut<'_, T> {
|
||||
DarkTreeIterMut { children: std::slice::from_mut(self), parent: None, parent_leaf: None }
|
||||
}
|
||||
}
|
||||
|
||||
/// Immutable iterator of a [`DarkTree`], performing DFS post-order
|
||||
/// traversal on the Tree leafs.
|
||||
struct DarkTreeIter<'a, T> {
|
||||
children: &'a [DarkTree<T>],
|
||||
parent: Option<Box<DarkTreeIter<'a, T>>>,
|
||||
@@ -74,6 +101,10 @@ impl<T> Default for DarkTreeIter<'_, T> {
|
||||
impl<'a, T> Iterator for DarkTreeIter<'a, T> {
|
||||
type Item = &'a DarkLeaf<T>;
|
||||
|
||||
/// Grab next item iterator visits and return
|
||||
/// its immutable reference, or recursively
|
||||
/// create and continue iteration on current
|
||||
/// leaf's children.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.children.first() {
|
||||
None => match self.parent.take() {
|
||||
@@ -102,6 +133,10 @@ impl<'a, T> Iterator for DarkTreeIter<'a, T> {
|
||||
|
||||
impl<T> FusedIterator for DarkTreeIter<'_, T> {}
|
||||
|
||||
/// Define fusion iteration behavior, allowing
|
||||
/// us to use the [`DarkTreeIter`] iterator in
|
||||
/// loops directly, without using .iter() method
|
||||
/// of [`DarkTree`].
|
||||
impl<'a, T> IntoIterator for &'a DarkTree<T> {
|
||||
type Item = &'a DarkLeaf<T>;
|
||||
|
||||
@@ -112,6 +147,8 @@ impl<'a, T> IntoIterator for &'a DarkTree<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutable iterator of a [`DarkTree`], performing DFS post-order
|
||||
/// traversal on the Tree leafs.
|
||||
struct DarkTreeIterMut<'a, T> {
|
||||
children: &'a mut [DarkTree<T>],
|
||||
parent: Option<Box<DarkTreeIterMut<'a, T>>>,
|
||||
@@ -127,6 +164,10 @@ impl<T> Default for DarkTreeIterMut<'_, T> {
|
||||
impl<'a, T> Iterator for DarkTreeIterMut<'a, T> {
|
||||
type Item = &'a mut DarkLeaf<T>;
|
||||
|
||||
/// Grab next item iterator visits and return
|
||||
/// its mutable reference, or recursively
|
||||
/// create and continue iteration on current
|
||||
/// leaf's children.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let children = mem::take(&mut self.children);
|
||||
match children.split_first_mut() {
|
||||
@@ -155,6 +196,10 @@ impl<'a, T> Iterator for DarkTreeIterMut<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Define fusion iteration behavior, allowing
|
||||
/// us to use the [`DarkTreeIterMut`] iterator
|
||||
/// in loops directly, without using .iter_mut()
|
||||
/// method of [`DarkTree`].
|
||||
impl<'a, T> IntoIterator for &'a mut DarkTree<T> {
|
||||
type Item = &'a mut DarkLeaf<T>;
|
||||
|
||||
@@ -165,6 +210,9 @@ impl<'a, T> IntoIterator for &'a mut DarkTree<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Special iterator of a [`DarkTree`], performing DFS post-order
|
||||
/// traversal on the Tree leafs, consuming each leaf. Since this
|
||||
/// iterator consumes the tree, it becomes unusable after it's moved.
|
||||
struct DarkTreeIntoIter<T> {
|
||||
children: VecDeque<DarkTree<T>>,
|
||||
parent: Option<Box<DarkTreeIntoIter<T>>>,
|
||||
@@ -179,6 +227,15 @@ impl<T> Default for DarkTreeIntoIter<T> {
|
||||
impl<T> Iterator for DarkTreeIntoIter<T> {
|
||||
type Item = DarkLeaf<T>;
|
||||
|
||||
/// Grab next item iterator visits, and return
|
||||
/// its mutable reference, or recursively
|
||||
/// create and continue iteration on current
|
||||
/// leaf's children.
|
||||
|
||||
/// Move next item iterator visits from the tree
|
||||
/// to the iterator consumer, if it has no children.
|
||||
/// Otherwise recursively create and continue iteration
|
||||
/// on current leaf's children, and moving it after them.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.children.pop_front() {
|
||||
None => match self.parent.take() {
|
||||
@@ -210,6 +267,10 @@ impl<T> Iterator for DarkTreeIntoIter<T> {
|
||||
|
||||
impl<T> FusedIterator for DarkTreeIntoIter<T> {}
|
||||
|
||||
/// Define fusion iteration behavior, allowing
|
||||
/// us to use the [`DarkTreeIntoIter`] .into_iter()
|
||||
/// method, to consume the [`DarkTree`] and iterate
|
||||
/// over it.
|
||||
impl<T> IntoIterator for DarkTree<T> {
|
||||
type Item = DarkLeaf<T>;
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
use crate::DarkTree;
|
||||
|
||||
/// Gereate a predefined [`DarkTree`] along with its
|
||||
/// expected traversal order.
|
||||
fn generate_tree() -> (DarkTree<i32>, Vec<i32>) {
|
||||
let tree = DarkTree::new(
|
||||
5,
|
||||
@@ -36,9 +38,17 @@ fn generate_tree() -> (DarkTree<i32>, Vec<i32>) {
|
||||
pub fn test_darktree_iterator() {
|
||||
let (tree, traversal_order) = generate_tree();
|
||||
|
||||
// Use [`DarkTree`] iterator to collect current
|
||||
// data, in order
|
||||
let nums: Vec<i32> = tree.iter().map(|x| x.data).collect();
|
||||
|
||||
// Verify iterator collected the data in the expected
|
||||
// traversal order.
|
||||
assert_eq!(nums, traversal_order);
|
||||
|
||||
// Verify using iterator indexing methods to retrieve
|
||||
// data from it, returns the expected one, as per
|
||||
// expected traversal order.
|
||||
assert_eq!(tree.iter().nth(1).unwrap().data, traversal_order[1]);
|
||||
}
|
||||
|
||||
@@ -46,26 +56,46 @@ pub fn test_darktree_iterator() {
|
||||
fn test_darktree_traversal_order() {
|
||||
let (mut tree, traversal_order) = generate_tree();
|
||||
|
||||
// Loop using the fusion immutable iterator,
|
||||
// verifying we grab the correct [`DarkLeaf`]
|
||||
// immutable reference, as per expected
|
||||
// traversal order.
|
||||
let mut index = 0;
|
||||
for leaf in &tree {
|
||||
assert_eq!(leaf.data, traversal_order[index]);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// Loop using the fusion mutable iterator,
|
||||
// verifying we grab the correct [`DarkLeaf`]
|
||||
// mutable reference, as per expected traversal
|
||||
// order.
|
||||
index = 0;
|
||||
for leaf in &mut tree {
|
||||
assert_eq!(leaf.data, traversal_order[index]);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// Loop using [`DarkTree`] .iter_mut() mutable
|
||||
// iterator, verifying we grab the correct [`DarkLeaf`]
|
||||
// mutable reference, as per expected traversal
|
||||
// order.
|
||||
for (index, leaf) in tree.iter_mut().enumerate() {
|
||||
assert_eq!(leaf.data, traversal_order[index]);
|
||||
}
|
||||
|
||||
// Loop using [`DarkTree`] .iter() immutable
|
||||
// iterator, verifying we grab the correct [`DarkLeaf`]
|
||||
// immutable reference, as per expected traversal
|
||||
// order.
|
||||
for (index, leaf) in tree.iter().enumerate() {
|
||||
assert_eq!(leaf.data, traversal_order[index]);
|
||||
}
|
||||
|
||||
// Loop using [`DarkTree`] .into_iter() iterator,
|
||||
// which consumes (moves) the tree, verifying we
|
||||
// collect the correct [`DarkLeaf`], as per expected
|
||||
// traversal order.
|
||||
for (index, leaf) in tree.into_iter().enumerate() {
|
||||
assert_eq!(leaf.data, traversal_order[index]);
|
||||
}
|
||||
@@ -75,14 +105,22 @@ fn test_darktree_traversal_order() {
|
||||
fn test_darktree_mut_iterator() {
|
||||
let (mut tree, _) = generate_tree();
|
||||
|
||||
// Loop using [`DarkTree`] .iter_mut() mutable
|
||||
// iterator, grabing a mutable reference over a
|
||||
// [`DarkLeaf`], and mutating its inner data.
|
||||
for leaf in tree.iter_mut() {
|
||||
leaf.data += 1;
|
||||
}
|
||||
|
||||
// Loop using the fusion mutable iterator,
|
||||
// grabing a mutable reference over a
|
||||
// [`DarkLeaf`], and mutating its inner data.
|
||||
for leaf in &mut tree {
|
||||
leaf.data += 1;
|
||||
}
|
||||
|
||||
// Verify performed mutation actually happened
|
||||
// on original tree.
|
||||
assert_eq!(
|
||||
tree,
|
||||
DarkTree::new(
|
||||
|
||||
Reference in New Issue
Block a user