mirror of
https://github.com/chylex/Bark-Browser.git
synced 2024-11-25 16:42:53 +01:00
Compare commits
3 Commits
995e0fc8f8
...
63b56de63f
Author | SHA1 | Date | |
---|---|---|---|
63b56de63f | |||
dace27d259 | |||
5f332677a7 |
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -311,7 +311,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "slab_tree"
|
||||
version = "0.3.2"
|
||||
source = "git+https://github.com/jsinger67/slab-tree.git?branch=set_root_fix#75a8dfa3b1f96f76ebe09e2e988deeffe6db54b6"
|
||||
dependencies = [
|
||||
"snowflake",
|
||||
]
|
||||
|
@ -21,5 +21,4 @@ slab_tree = "0.3.2"
|
||||
users = "0.11"
|
||||
|
||||
[patch.crates-io.slab_tree]
|
||||
git = "https://github.com/jsinger67/slab-tree.git"
|
||||
branch = "set_root_fix"
|
||||
path = "./lib/slab-tree"
|
||||
|
@ -42,3 +42,9 @@ Run `docker build --output out .` to build a release binary into the `out/` fold
|
||||
This project exists 1) because I couldn't find any tree-based file manager I liked and 2) because I wanted to have fun writing Rust, and I don't really want to spend time reading and reviewing pull requests.
|
||||
|
||||
For now, issues are closed, and I'm not accepting any major contributions — especially ones related to the roadmap. If you have a small idea, issue, or pull request, feel free to start a [discussion](https://github.com/chylex/Bark-Browser/discussions).
|
||||
|
||||
# Dependencies
|
||||
|
||||
For a full list of dependencies, see [Cargo.toml](Cargo.toml).
|
||||
|
||||
This repository includes the sources of [slab-tree](https://github.com/iwburns/slab-tree) (by [iwburns](https://github.com/iwburns)) with a [bug fix for `set_root`](https://github.com/iwburns/slab-tree/pull/28) (by [jsinger67](https://github.com/jsinger67)) and additional modifications from me.
|
||||
|
2
lib/slab-tree/.gitignore
vendored
Normal file
2
lib/slab-tree/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/.idea/
|
||||
/target/
|
16
lib/slab-tree/Cargo.lock
generated
Normal file
16
lib/slab-tree/Cargo.lock
generated
Normal file
@ -0,0 +1,16 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "slab_tree"
|
||||
version = "0.3.2"
|
||||
dependencies = [
|
||||
"snowflake",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snowflake"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1"
|
15
lib/slab-tree/Cargo.toml
Normal file
15
lib/slab-tree/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "slab_tree"
|
||||
version = "0.3.2"
|
||||
authors = ["Ian <iwburns8@gmail.com>"]
|
||||
description = "A vec-backed tree structure with tree-specific generational indexes."
|
||||
documentation = "https://docs.rs/slab_tree"
|
||||
repository = "https://github.com/iwburns/slab-tree"
|
||||
readme = "README.md"
|
||||
keywords = ["tree", "slab", "slab-tree"]
|
||||
categories = ["data-structures"]
|
||||
license = "MIT"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
snowflake = "1.3.0"
|
69
lib/slab-tree/README.md
Normal file
69
lib/slab-tree/README.md
Normal file
@ -0,0 +1,69 @@
|
||||
# slab_tree
|
||||
|
||||
[![Build Status](https://travis-ci.org/iwburns/slab-tree.svg?branch=master)](https://travis-ci.org/iwburns/slab-tree)
|
||||
[![](https://tokei.rs/b1/github/iwburns/slab-tree)](https://github.com/iwburns/slab-tree)
|
||||
|
||||
A vec-backed tree structure with tree-specific generational indexes.
|
||||
|
||||
## Overview
|
||||
|
||||
This library provides a `Tree<T>` struct which allows the creation and manipulation of in-memory trees.
|
||||
The tree itself is backed by a vector and the tree's node relationships are managed by tree-specific
|
||||
generational indexes called `NodeId`s (more below). In addition, "views" of tree nodes are handed out
|
||||
which are either immutable (`NodeRef`) or mutable (`NodeMut`) instead of handing out references
|
||||
directly. Most tree mutations are achieved by modifying `NodeMut`s instead of talking to the tree
|
||||
itself.
|
||||
|
||||
`Tree`s in this crate are "just" trees. They do not allow cycles, and they do not allow arbitrary
|
||||
graph structures to be created. Each node in the tree can have an arbitrary number of children, and
|
||||
there is no weight associated with edges between the nodes in the tree.
|
||||
|
||||
**Please Note:** this crate does not support comparison-based data insertion. In other words, this is
|
||||
not a binary search tree (or any other kind of search tree) crate. It is purely a crate for storing
|
||||
data in a hierarchical manner. The caller must know the structure that they wish to build and then use
|
||||
this crate to do so; this library will not make those structural decisions for you.
|
||||
|
||||
## Safety
|
||||
This crate uses `#![forbid(unsafe_code)]` to prevent any and all `unsafe` code usage.
|
||||
|
||||
## Example Usage
|
||||
```rust
|
||||
use slab_tree::*;
|
||||
|
||||
fn main() {
|
||||
|
||||
// "hello"
|
||||
// / \
|
||||
// "world" "trees"
|
||||
// |
|
||||
// "are"
|
||||
// |
|
||||
// "cool"
|
||||
|
||||
let mut tree = TreeBuilder::new().with_root("hello").build();
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let mut hello = tree.get_mut(root_id).unwrap();
|
||||
|
||||
hello.append("world");
|
||||
hello
|
||||
.append("trees")
|
||||
.append("are")
|
||||
.append("cool");
|
||||
}
|
||||
```
|
||||
|
||||
## `NodeId`s
|
||||
`NodeId`s are tree-specific generational indexes. Using generational indexes means that we can re-use
|
||||
space inside the tree (after nodes have been removed) without also having to re-use the same tree
|
||||
indexes which could potentially cause confusion and bugs. The "tree-specific" part means that indexes
|
||||
from one tree cannot be confused for indexes for another tree. This is because each index contains a
|
||||
process-unique-id which is shared by the tree from which that index originated.
|
||||
|
||||
## Project Goals
|
||||
* Allow caller control of as many allocations as possible (through pre-allocation)
|
||||
* Fast and Ergonomic Node insertion and removal
|
||||
* Arbitrary Tree structure creation and manipulation
|
||||
|
||||
## Non-Goals
|
||||
* Arbitrary _Graph_ structure creation and manipulation
|
||||
* Comparison-based node insertion of any kind
|
22
lib/slab-tree/src/behaviors.rs
Normal file
22
lib/slab-tree/src/behaviors.rs
Normal file
@ -0,0 +1,22 @@
|
||||
///
|
||||
/// Describes all the possible ways to remove a Node from a Tree.
|
||||
///
|
||||
pub enum RemoveBehavior {
|
||||
///
|
||||
/// All children of the removed Node will be dropped from the Tree. All children (and all
|
||||
/// Nodes in each of their sub-trees) will no longer exist in the Tree after this operation.
|
||||
///
|
||||
/// This is slower than `OrphanChildren` but frees up space inside the Tree.
|
||||
///
|
||||
DropChildren,
|
||||
|
||||
///
|
||||
/// All children of the removed Node will be left in the Tree (still accessible via NodeIds).
|
||||
/// However, each child (and their sub-trees) will no longer be connected to the rest of the
|
||||
/// Nodes in the Tree.
|
||||
///
|
||||
/// Orphaned nodes will live in the Tree until they are manually removed or until the Tree is
|
||||
/// Dropped. This is faster than `DropChildren` but doesn't free up any space inside the Tree.
|
||||
///
|
||||
OrphanChildren,
|
||||
}
|
136
lib/slab-tree/src/core_tree.rs
Normal file
136
lib/slab-tree/src/core_tree.rs
Normal file
@ -0,0 +1,136 @@
|
||||
use crate::node::Node;
|
||||
use crate::slab;
|
||||
use crate::NodeId;
|
||||
use snowflake::ProcessUniqueId;
|
||||
|
||||
///
|
||||
/// A wrapper around a Slab containing Node<T> values.
|
||||
///
|
||||
/// Groups a collection of Node<T>s with a process unique id.
|
||||
///
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) struct CoreTree<T> {
|
||||
id: ProcessUniqueId,
|
||||
slab: slab::Slab<Node<T>>,
|
||||
}
|
||||
|
||||
impl<T> CoreTree<T> {
|
||||
pub(crate) fn new(capacity: usize) -> CoreTree<T> {
|
||||
CoreTree {
|
||||
id: ProcessUniqueId::new(),
|
||||
slab: slab::Slab::new(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn capacity(&self) -> usize {
|
||||
self.slab.capacity()
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, data: T) -> NodeId {
|
||||
let key = self.slab.insert(Node::new(data));
|
||||
self.new_node_id(key)
|
||||
}
|
||||
|
||||
pub(crate) fn remove(&mut self, node_id: NodeId) -> Option<T> {
|
||||
self.filter_by_tree_id(node_id)
|
||||
.and_then(|id| self.slab.remove(id.index))
|
||||
.map(|node| node.data)
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, node_id: NodeId) -> Option<&Node<T>> {
|
||||
self.filter_by_tree_id(node_id)
|
||||
.and_then(|id| self.slab.get(id.index))
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut(&mut self, node_id: NodeId) -> Option<&mut Node<T>> {
|
||||
self.filter_by_tree_id(node_id)
|
||||
.and_then(move |id| self.slab.get_mut(id.index))
|
||||
}
|
||||
|
||||
fn new_node_id(&self, index: slab::Index) -> NodeId {
|
||||
NodeId {
|
||||
tree_id: self.id,
|
||||
index,
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_by_tree_id(&self, node_id: NodeId) -> Option<NodeId> {
|
||||
if node_id.tree_id != self.id {
|
||||
return None;
|
||||
}
|
||||
Some(node_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn capacity() {
|
||||
let capacity = 5;
|
||||
let tree = CoreTree::<i32>::new(capacity);
|
||||
assert_eq!(tree.capacity(), capacity);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert() {
|
||||
let mut tree = CoreTree::new(0);
|
||||
|
||||
let id = tree.insert(1);
|
||||
let id2 = tree.insert(3);
|
||||
|
||||
assert_eq!(tree.get(id).unwrap().data, 1);
|
||||
assert_eq!(tree.get(id2).unwrap().data, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove() {
|
||||
let mut tree = CoreTree::new(0);
|
||||
|
||||
let id = tree.insert(1);
|
||||
assert_eq!(tree.get(id).unwrap().data, 1);
|
||||
|
||||
let one = tree.remove(id);
|
||||
assert!(one.is_some());
|
||||
|
||||
let one = one.unwrap();
|
||||
assert_eq!(one, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get() {
|
||||
let mut tree = CoreTree::new(0);
|
||||
|
||||
let id = tree.insert(1);
|
||||
let id2 = tree.insert(3);
|
||||
|
||||
assert_eq!(tree.get(id).unwrap().data, 1);
|
||||
assert_eq!(tree.get(id2).unwrap().data, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mut() {
|
||||
let mut tree = CoreTree::new(0);
|
||||
|
||||
let id = tree.insert(1);
|
||||
let id2 = tree.insert(3);
|
||||
|
||||
assert_eq!(tree.get_mut(id).unwrap().data, 1);
|
||||
assert_eq!(tree.get_mut(id2).unwrap().data, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_with_bad_id() {
|
||||
let mut tree = CoreTree::new(0);
|
||||
let tree2: CoreTree<i32> = CoreTree::new(0);
|
||||
|
||||
let mut id = tree.insert(1);
|
||||
id.tree_id = tree2.id; // oops, wrong tree id.
|
||||
|
||||
let result = tree.get(id);
|
||||
|
||||
assert!(result.is_none());
|
||||
}
|
||||
}
|
223
lib/slab-tree/src/iter.rs
Normal file
223
lib/slab-tree/src/iter.rs
Normal file
@ -0,0 +1,223 @@
|
||||
use crate::node::*;
|
||||
use crate::tree::Tree;
|
||||
use crate::NodeId;
|
||||
|
||||
// todo: document this
|
||||
|
||||
pub struct Ancestors<'a, T> {
|
||||
node_id: Option<NodeId>,
|
||||
tree: &'a Tree<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Ancestors<'a, T> {
|
||||
pub(crate) fn new(node_id: Option<NodeId>, tree: &'a Tree<T>) -> Ancestors<T> {
|
||||
Ancestors { node_id, tree }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for Ancestors<'a, T> {
|
||||
type Item = NodeRef<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||
self.node_id
|
||||
.take()
|
||||
.and_then(|node_id| self.tree.get_node_relatives(node_id).parent)
|
||||
.map(|id| {
|
||||
self.node_id = Some(id);
|
||||
NodeRef::new(id, self.tree)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// possibly re-name this, not sure how I feel about it
|
||||
pub struct NextSiblings<'a, T> {
|
||||
node_id: Option<NodeId>,
|
||||
tree: &'a Tree<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> NextSiblings<'a, T> {
|
||||
pub(crate) fn new(node_id: Option<NodeId>, tree: &'a Tree<T>) -> NextSiblings<T> {
|
||||
NextSiblings { node_id, tree }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for NextSiblings<'a, T> {
|
||||
type Item = NodeRef<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||
self.node_id.take().map(|node_id| {
|
||||
self.node_id = self.tree.get_node_relatives(node_id).next_sibling;
|
||||
NodeRef::new(node_id, self.tree)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Depth-first pre-order iterator
|
||||
pub struct PreOrder<'a, T> {
|
||||
start: Option<NodeRef<'a, T>>,
|
||||
children: Vec<NextSiblings<'a, T>>,
|
||||
tree: &'a Tree<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> PreOrder<'a, T> {
|
||||
pub(crate) fn new(node: &NodeRef<'a, T>, tree: &'a Tree<T>) -> PreOrder<'a, T> {
|
||||
let children = vec![];
|
||||
let start = tree.get(node.node_id());
|
||||
PreOrder {
|
||||
start,
|
||||
children,
|
||||
tree,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for PreOrder<'a, T> {
|
||||
type Item = NodeRef<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||
if let Some(node) = self.start.take() {
|
||||
let first_child_id = node.first_child().map(|child_ref| child_ref.node_id());
|
||||
self.children
|
||||
.push(NextSiblings::new(first_child_id, self.tree));
|
||||
Some(node)
|
||||
} else {
|
||||
while !self.children.is_empty() {
|
||||
if let Some(node_ref) = self.children.last_mut().and_then(Iterator::next) {
|
||||
if let Some(first_child) = node_ref.first_child() {
|
||||
self.children
|
||||
.push(NextSiblings::new(Some(first_child.node_id()), self.tree));
|
||||
}
|
||||
return Some(node_ref);
|
||||
}
|
||||
self.children.pop();
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Depth-first post-order iterator
|
||||
pub struct PostOrder<'a, T> {
|
||||
nodes: Vec<(NodeRef<'a, T>, NextSiblings<'a, T>)>,
|
||||
tree: &'a Tree<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> PostOrder<'a, T> {
|
||||
pub(crate) fn new(node: &NodeRef<'a, T>, tree: &'a Tree<T>) -> PostOrder<'a, T> {
|
||||
let node = tree
|
||||
.get(node.node_id())
|
||||
.expect("getting node of node ref id");
|
||||
let first_child_id = node.first_child().map(|first_child| first_child.node_id());
|
||||
let nodes = vec![(node, NextSiblings::new(first_child_id, tree))];
|
||||
PostOrder { nodes, tree }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for PostOrder<'a, T> {
|
||||
type Item = NodeRef<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||
if let Some((node, mut children)) = self.nodes.pop() {
|
||||
if let Some(next) = children.next() {
|
||||
self.nodes.push((node, children));
|
||||
let mut node_id = next.node_id();
|
||||
loop {
|
||||
let node = self.tree.get(node_id).expect("getting node of node ref id");
|
||||
if let Some(first_child) = node.first_child() {
|
||||
node_id = first_child.node_id();
|
||||
let mut children = NextSiblings::new(Some(node_id), self.tree);
|
||||
assert!(children.next().is_some(), "skipping first child");
|
||||
self.nodes.push((node, children));
|
||||
} else {
|
||||
break Some(node);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Some(node)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Depth-first level-order iterator
|
||||
pub struct LevelOrder<'a, T> {
|
||||
start: NodeRef<'a, T>,
|
||||
levels: Vec<(NodeId, NextSiblings<'a, T>)>,
|
||||
tree: &'a Tree<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> LevelOrder<'a, T> {
|
||||
pub(crate) fn new(node: &NodeRef<'a, T>, tree: &'a Tree<T>) -> LevelOrder<'a, T> {
|
||||
let start = tree
|
||||
.get(node.node_id())
|
||||
.expect("getting node of node ref id");
|
||||
let levels = Vec::new();
|
||||
LevelOrder {
|
||||
start,
|
||||
levels,
|
||||
tree,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for LevelOrder<'a, T> {
|
||||
type Item = NodeRef<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||
if self.levels.is_empty() {
|
||||
let first_child_id = self.start.first_child().map(|child| child.node_id());
|
||||
self.levels.push((
|
||||
self.start.node_id(),
|
||||
NextSiblings::new(first_child_id, self.tree),
|
||||
));
|
||||
let node = self
|
||||
.tree
|
||||
.get(self.start.node_id())
|
||||
.expect("getting node of existing node ref id");
|
||||
Some(node)
|
||||
} else {
|
||||
let mut on_level = self.levels.len();
|
||||
let next_level = on_level + 1;
|
||||
let mut level = on_level;
|
||||
while level > 0 {
|
||||
if let Some(node) = self.levels.last_mut().expect("non-empty levels").1.next() {
|
||||
if level >= on_level {
|
||||
return Some(node);
|
||||
} else {
|
||||
let first_child_id = node.first_child().map(|child| child.node_id());
|
||||
self.levels
|
||||
.push((node.node_id(), NextSiblings::new(first_child_id, self.tree)));
|
||||
level += 1;
|
||||
}
|
||||
} else {
|
||||
let (node_id, _) = self.levels.pop().expect("on level > 0");
|
||||
if let Some(next) = self.levels.last_mut().and_then(|level| level.1.next()) {
|
||||
let first_child_id = next.first_child().map(|child| child.node_id());
|
||||
self.levels
|
||||
.push((next.node_id(), NextSiblings::new(first_child_id, self.tree)));
|
||||
} else if level == 1 {
|
||||
if on_level < next_level {
|
||||
on_level += 1;
|
||||
let node = self
|
||||
.tree
|
||||
.get(node_id)
|
||||
.expect("getting node of existing node ref id");
|
||||
let first_child_id = node.first_child().map(|child| child.node_id());
|
||||
self.levels.push((
|
||||
node.node_id(),
|
||||
NextSiblings::new(first_child_id, self.tree),
|
||||
));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
level -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
96
lib/slab-tree/src/lib.rs
Normal file
96
lib/slab-tree/src/lib.rs
Normal file
@ -0,0 +1,96 @@
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//!
|
||||
//! # slab_tree
|
||||
//!
|
||||
//! [![Build Status](https://travis-ci.org/iwburns/slab-tree.svg?branch=master)](https://travis-ci.org/iwburns/slab-tree)
|
||||
//! [![](https://tokei.rs/b1/github/iwburns/slab-tree)](https://github.com/iwburns/slab-tree)
|
||||
//!
|
||||
//! A vec-backed tree structure with tree-specific generational indexes.
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! This library provides a `Tree<T>` struct which allows the creation and manipulation of in-memory trees.
|
||||
//! The tree itself is backed by a vector and the tree's node relationships are managed by tree-specific
|
||||
//! generational indexes called `NodeId`s (more below). In addition, "views" of tree nodes are handed out
|
||||
//! which are either immutable (`NodeRef`) or mutable (`NodeMut`) instead of handing out references
|
||||
//! directly. Most tree mutations are achieved by modifying `NodeMut`s instead of talking to the tree
|
||||
//! itself.
|
||||
//!
|
||||
//! `Tree`s in this crate are "just" trees. They do not allow cycles, and they do not allow arbitrary
|
||||
//! graph structures to be created. Each node in the tree can have an arbitrary number of children, and
|
||||
//! there is no weight associated with edges between the nodes in the tree.
|
||||
//!
|
||||
//! **Please Note:** this crate does not support comparison-based data insertion. In other words, this is
|
||||
//! not a binary search tree (or any other kind of search tree) crate. It is purely a crate for storing
|
||||
//! data in a hierarchical manner. The caller must know the structure that they wish to build and then use
|
||||
//! this crate to do so; this library will not make those structural decisions for you.
|
||||
//!
|
||||
//! ## Safety
|
||||
//! This crate uses `#![forbid(unsafe_code)]` to prevent any and all `unsafe` code usage.
|
||||
//!
|
||||
//! ## Example Usage
|
||||
//! ```
|
||||
//! use slab_tree::*;
|
||||
//!
|
||||
//! // "hello"
|
||||
//! // / \
|
||||
//! // "world" "trees"
|
||||
//! // |
|
||||
//! // "are"
|
||||
//! // |
|
||||
//! // "cool"
|
||||
//!
|
||||
//! let mut tree = TreeBuilder::new().with_root("hello").build();
|
||||
//! let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
//! let mut hello = tree.get_mut(root_id).unwrap();
|
||||
//!
|
||||
//! hello.append("world");
|
||||
//! hello
|
||||
//! .append("trees")
|
||||
//! .append("are")
|
||||
//! .append("cool");
|
||||
//! ```
|
||||
//!
|
||||
//! ## `NodeId`s
|
||||
//! `NodeId`s are tree-specific generational indexes. Using generational indexes means that we can re-use
|
||||
//! space inside the tree (after nodes have been removed) without also having to re-use the same tree
|
||||
//! indexes which could potentially cause confusion and bugs. The "tree-specific" part means that indexes
|
||||
//! from one tree cannot be confused for indexes for another tree. This is because each index contains a
|
||||
//! process-unique-id which is shared by the tree from which that index originated.
|
||||
//!
|
||||
//! ## Project Goals
|
||||
//! * Allow caller control of as many allocations as possible (through pre-allocation)
|
||||
//! * Fast and Ergonomic Node insertion and removal
|
||||
//! * Arbitrary Tree structure creation and manipulation
|
||||
//!
|
||||
//! ## Non-Goals
|
||||
//! * Arbitrary _Graph_ structure creation and manipulation
|
||||
//! * Comparison-based node insertion of any kind
|
||||
//!
|
||||
|
||||
pub mod behaviors;
|
||||
mod core_tree;
|
||||
pub mod iter;
|
||||
pub mod node;
|
||||
mod slab;
|
||||
pub mod tree;
|
||||
|
||||
pub use crate::behaviors::RemoveBehavior;
|
||||
pub use crate::iter::Ancestors;
|
||||
pub use crate::iter::NextSiblings;
|
||||
pub use crate::node::NodeMut;
|
||||
pub use crate::node::NodeRef;
|
||||
pub use crate::tree::Tree;
|
||||
pub use crate::tree::TreeBuilder;
|
||||
use snowflake::ProcessUniqueId;
|
||||
|
||||
///
|
||||
/// An identifier used to differentiate between Nodes and tie
|
||||
/// them to a specific tree.
|
||||
///
|
||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||
pub struct NodeId {
|
||||
tree_id: ProcessUniqueId,
|
||||
index: slab::Index,
|
||||
}
|
39
lib/slab-tree/src/node.rs
Normal file
39
lib/slab-tree/src/node.rs
Normal file
@ -0,0 +1,39 @@
|
||||
mod bark_extensions;
|
||||
mod node_mut;
|
||||
mod node_ref;
|
||||
|
||||
pub use self::bark_extensions::*;
|
||||
pub use self::node_mut::NodeMut;
|
||||
pub use self::node_ref::NodeRef;
|
||||
|
||||
use crate::NodeId;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub(crate) struct Relatives {
|
||||
pub(crate) parent: Option<NodeId>,
|
||||
pub(crate) prev_sibling: Option<NodeId>,
|
||||
pub(crate) next_sibling: Option<NodeId>,
|
||||
pub(crate) first_child: Option<NodeId>,
|
||||
pub(crate) last_child: Option<NodeId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) struct Node<T> {
|
||||
pub(crate) data: T,
|
||||
pub(crate) relatives: Relatives,
|
||||
}
|
||||
|
||||
impl<T> Node<T> {
|
||||
pub(crate) fn new(data: T) -> Node<T> {
|
||||
Node {
|
||||
data,
|
||||
relatives: Relatives {
|
||||
parent: None,
|
||||
prev_sibling: None,
|
||||
next_sibling: None,
|
||||
first_child: None,
|
||||
last_child: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
79
lib/slab-tree/src/node/bark_extensions.rs
Normal file
79
lib/slab-tree/src/node/bark_extensions.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use crate::NodeId;
|
||||
use crate::NodeMut;
|
||||
use crate::NodeRef;
|
||||
|
||||
impl<'a, T> NodeRef<'a, T> {
|
||||
pub fn parent_id(&self) -> Option<NodeId> {
|
||||
self.parent().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn first_child_id(&self) -> Option<NodeId> {
|
||||
self.first_child().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn last_child_id(&self) -> Option<NodeId> {
|
||||
self.last_child().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn prev_sibling_id(&self) -> Option<NodeId> {
|
||||
self.prev_sibling().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn next_sibling_id(&self) -> Option<NodeId> {
|
||||
self.next_sibling().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn last_descendant_or_self(&self) -> NodeRef<'a, T> {
|
||||
let mut node = NodeRef::new(self.node_id(), self.tree);
|
||||
|
||||
while let Some(id) = node.get_self_as_node().relatives.last_child {
|
||||
node = NodeRef::new(id, self.tree);
|
||||
}
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
pub fn above(&self) -> Option<NodeRef<T>> {
|
||||
if let Some(prev_sibling) = self.prev_sibling() {
|
||||
Some(prev_sibling.last_descendant_or_self())
|
||||
} else {
|
||||
self.parent()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn above_id(&self) -> Option<NodeId> {
|
||||
self.above().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn below(&self) -> Option<NodeRef<T>> {
|
||||
self.first_child()
|
||||
.or_else(|| self.next_sibling())
|
||||
.or_else(|| self.ancestors().find_map(|ancestor| ancestor.next_sibling_id()).map(|id| NodeRef::new(id, self.tree)))
|
||||
}
|
||||
|
||||
pub fn below_id(&self) -> Option<NodeId> {
|
||||
self.below().map(|node| node.node_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> NodeMut<'a, T> {
|
||||
pub fn parent_id(&mut self) -> Option<NodeId> {
|
||||
self.parent().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn first_child_id(&mut self) -> Option<NodeId> {
|
||||
self.first_child().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn last_child_id(&mut self) -> Option<NodeId> {
|
||||
self.last_child().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn prev_sibling_id(&mut self) -> Option<NodeId> {
|
||||
self.prev_sibling().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
pub fn next_sibling_id(&mut self) -> Option<NodeId> {
|
||||
self.next_sibling().map(|node| node.node_id())
|
||||
}
|
||||
}
|
1399
lib/slab-tree/src/node/node_mut.rs
Normal file
1399
lib/slab-tree/src/node/node_mut.rs
Normal file
File diff suppressed because it is too large
Load Diff
381
lib/slab-tree/src/node/node_ref.rs
Normal file
381
lib/slab-tree/src/node/node_ref.rs
Normal file
@ -0,0 +1,381 @@
|
||||
use crate::iter::Ancestors;
|
||||
use crate::iter::LevelOrder;
|
||||
use crate::iter::NextSiblings;
|
||||
use crate::iter::PostOrder;
|
||||
use crate::iter::PreOrder;
|
||||
use crate::node::Node;
|
||||
use crate::tree::Tree;
|
||||
use crate::NodeId;
|
||||
|
||||
///
|
||||
/// An immutable reference to a given `Node`'s data and its relatives.
|
||||
///
|
||||
pub struct NodeRef<'a, T> {
|
||||
pub(super) node_id: NodeId,
|
||||
pub(super) tree: &'a Tree<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> NodeRef<'a, T> {
|
||||
pub(crate) fn new(node_id: NodeId, tree: &'a Tree<T>) -> NodeRef<T> {
|
||||
NodeRef { node_id, tree }
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the `NodeId` that identifies this `Node` in the tree.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
/// let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
/// let root = tree.root_mut().expect("root doesn't exist?");
|
||||
///
|
||||
/// let root_id_again = root.as_ref().node_id();
|
||||
///
|
||||
/// assert_eq!(root_id_again, root_id);
|
||||
/// ```
|
||||
///
|
||||
pub fn node_id(&self) -> NodeId {
|
||||
self.node_id
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a reference to the data contained by the given `Node`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
///
|
||||
/// let root = tree.root().expect("root doesn't exist?");
|
||||
///
|
||||
/// assert_eq!(root.data(), &1);
|
||||
/// ```
|
||||
///
|
||||
pub fn data(&self) -> &'a T {
|
||||
if let Some(node) = self.tree.get_node(self.node_id) {
|
||||
&node.data
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `NodeRef` pointing to this `Node`'s parent. Returns a `Some`-value containing
|
||||
/// the `NodeRef` if this `Node` has a parent; otherwise returns a `None`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
///
|
||||
/// let root = tree.root().expect("root doesn't exist?");
|
||||
///
|
||||
/// assert!(root.parent().is_none());
|
||||
/// ```
|
||||
///
|
||||
pub fn parent(&self) -> Option<NodeRef<T>> {
|
||||
self.get_self_as_node()
|
||||
.relatives
|
||||
.parent
|
||||
.map(|id| NodeRef::new(id, self.tree))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `NodeRef` pointing to this `Node`'s previous sibling. Returns a `Some`-value
|
||||
/// containing the `NodeRef` if this `Node` has a previous sibling; otherwise returns a `None`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
///
|
||||
/// let root = tree.root().expect("root doesn't exist?");
|
||||
///
|
||||
/// assert!(root.prev_sibling().is_none());
|
||||
/// ```
|
||||
///
|
||||
pub fn prev_sibling(&self) -> Option<NodeRef<T>> {
|
||||
self.get_self_as_node()
|
||||
.relatives
|
||||
.prev_sibling
|
||||
.map(|id| NodeRef::new(id, self.tree))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `NodeRef` pointing to this `Node`'s next sibling. Returns a `Some`-value
|
||||
/// containing the `NodeRef` if this `Node` has a next sibling; otherwise returns a `None`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
///
|
||||
/// let root = tree.root().expect("root doesn't exist?");
|
||||
///
|
||||
/// assert!(root.next_sibling().is_none());
|
||||
/// ```
|
||||
///
|
||||
pub fn next_sibling(&self) -> Option<NodeRef<T>> {
|
||||
self.get_self_as_node()
|
||||
.relatives
|
||||
.next_sibling
|
||||
.map(|id| NodeRef::new(id, self.tree))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `NodeRef` pointing to this `Node`'s first child. Returns a `Some`-value
|
||||
/// containing the `NodeRef` if this `Node` has a first child; otherwise returns a `None`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
///
|
||||
/// let root = tree.root().expect("root doesn't exist?");
|
||||
///
|
||||
/// assert!(root.first_child().is_none());
|
||||
/// ```
|
||||
///
|
||||
pub fn first_child(&self) -> Option<NodeRef<T>> {
|
||||
self.get_self_as_node()
|
||||
.relatives
|
||||
.first_child
|
||||
.map(|id| NodeRef::new(id, self.tree))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `NodeRef` pointing to this `Node`'s last child. Returns a `Some`-value
|
||||
/// containing the `NodeRef` if this `Node` has a last child; otherwise returns a `None`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
///
|
||||
/// let root = tree.root().expect("root doesn't exist?");
|
||||
///
|
||||
/// assert!(root.last_child().is_none());
|
||||
/// ```
|
||||
///
|
||||
pub fn last_child(&self) -> Option<NodeRef<T>> {
|
||||
self.get_self_as_node()
|
||||
.relatives
|
||||
.last_child
|
||||
.map(|id| NodeRef::new(id, self.tree))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `Iterator` over the given `Node`'s ancestors. Each call to `Iterator::next()`
|
||||
/// returns a `NodeRef` pointing to the current `Node`'s parent.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
///
|
||||
/// let leaf_id = tree.root_mut().expect("root doesn't exist?")
|
||||
/// .append(2)
|
||||
/// .append(3)
|
||||
/// .append(4)
|
||||
/// .node_id();
|
||||
///
|
||||
/// let leaf = tree.get(leaf_id).unwrap();
|
||||
///
|
||||
/// let values = [3, 2, 1];
|
||||
/// for (i, ancestor) in leaf.ancestors().enumerate() {
|
||||
/// assert_eq!(ancestor.data(), &values[i]);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub fn ancestors(&self) -> Ancestors<'a, T> {
|
||||
Ancestors::new(Some(self.node_id), self.tree)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `Iterator` over the given `Node`'s children. Each call to `Iterator::next()`
|
||||
/// returns a `NodeRef` pointing to the next child of the given `Node`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
///
|
||||
/// let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||
/// root.append(2);
|
||||
/// root.append(3);
|
||||
/// root.append(4);
|
||||
///
|
||||
/// let root = root.as_ref();
|
||||
///
|
||||
/// let values = [2, 3, 4];
|
||||
/// for (i, child) in root.children().enumerate() {
|
||||
/// assert_eq!(child.data(), &values[i]);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub fn children(&self) -> NextSiblings<'a, T> {
|
||||
let first_child_id = self.tree.get_node_relatives(self.node_id).first_child;
|
||||
NextSiblings::new(first_child_id, self.tree)
|
||||
}
|
||||
|
||||
/// Depth-first pre-order traversal.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(0i64).build();
|
||||
/// let root_id = tree.root().unwrap().node_id();
|
||||
/// let one_id = tree.get_mut(root_id).unwrap().append(1).node_id();
|
||||
/// tree.get_mut(one_id).unwrap().append(2);
|
||||
/// tree.get_mut(one_id).unwrap().append(3);
|
||||
/// tree.get_mut(root_id).unwrap().append(4);
|
||||
/// let pre_order = tree.root().unwrap().traverse_pre_order()
|
||||
/// .map(|node_ref| node_ref.data().clone()).collect::<Vec<i64>>();
|
||||
/// assert_eq!(pre_order, vec![0, 1, 2, 3, 4]);
|
||||
/// ```
|
||||
pub fn traverse_pre_order(&self) -> PreOrder<'a, T> {
|
||||
PreOrder::new(self, self.tree)
|
||||
}
|
||||
|
||||
/// Depth-first post-order traversal.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(0i64).build();
|
||||
/// let root_id = tree.root().unwrap().node_id();
|
||||
/// let one_id = tree.get_mut(root_id).unwrap().append(1).node_id();
|
||||
/// tree.get_mut(one_id).unwrap().append(2);
|
||||
/// tree.get_mut(one_id).unwrap().append(3);
|
||||
/// tree.get_mut(root_id).unwrap().append(4);
|
||||
/// let post_order = tree.root().unwrap().traverse_post_order()
|
||||
/// .map(|node_ref| node_ref.data().clone()).collect::<Vec<i64>>();
|
||||
/// assert_eq!(post_order, vec![2, 3, 1, 4, 0]);
|
||||
/// ```
|
||||
pub fn traverse_post_order(&self) -> PostOrder<'a, T> {
|
||||
PostOrder::new(self, self.tree)
|
||||
}
|
||||
|
||||
/// Depth-first level-order traversal.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(0i64).build();
|
||||
/// let root_id = tree.root().unwrap().node_id();
|
||||
/// let one_id = tree.get_mut(root_id).unwrap().append(1).node_id();
|
||||
/// tree.get_mut(one_id).unwrap().append(2);
|
||||
/// tree.get_mut(one_id).unwrap().append(3);
|
||||
/// tree.get_mut(root_id).unwrap().append(4);
|
||||
/// let level_order = tree.root().unwrap().traverse_level_order()
|
||||
/// .map(|node_ref| node_ref.data().clone()).collect::<Vec<i64>>();
|
||||
/// assert_eq!(level_order, vec![0, 1, 4, 2, 3]);
|
||||
/// ```
|
||||
pub fn traverse_level_order(&self) -> LevelOrder<'a, T> {
|
||||
LevelOrder::new(self, self.tree)
|
||||
}
|
||||
|
||||
pub(super) fn get_self_as_node(&self) -> &Node<T> {
|
||||
if let Some(node) = self.tree.get_node(self.node_id) {
|
||||
&node
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
#[cfg(test)]
|
||||
mod node_ref_tests {
|
||||
use crate::tree::Tree;
|
||||
|
||||
#[test]
|
||||
fn data() {
|
||||
let mut tree = Tree::new();
|
||||
tree.set_root(1);
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root_ref = tree.get(root_id).unwrap();
|
||||
assert_eq!(root_ref.data(), &1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parent() {
|
||||
let mut tree = Tree::new();
|
||||
tree.set_root(1);
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root_ref = tree.get(root_id).unwrap();
|
||||
assert!(root_ref.parent().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prev_sibling() {
|
||||
let mut tree = Tree::new();
|
||||
tree.set_root(1);
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root_ref = tree.get(root_id).unwrap();
|
||||
assert!(root_ref.prev_sibling().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn next_sibling() {
|
||||
let mut tree = Tree::new();
|
||||
tree.set_root(1);
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root_ref = tree.get(root_id).unwrap();
|
||||
assert!(root_ref.next_sibling().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_child() {
|
||||
let mut tree = Tree::new();
|
||||
tree.set_root(1);
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root_ref = tree.get(root_id).unwrap();
|
||||
assert!(root_ref.first_child().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn last_child() {
|
||||
let mut tree = Tree::new();
|
||||
tree.set_root(1);
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root_ref = tree.get(root_id).unwrap();
|
||||
assert!(root_ref.last_child().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ancestors() {
|
||||
let mut tree = Tree::new();
|
||||
tree.set_root(1);
|
||||
|
||||
let mut root_mut = tree.root_mut().expect("root doesn't exist");
|
||||
let node_id = root_mut.append(2).append(3).append(4).append(5).node_id();
|
||||
|
||||
let values = [4, 3, 2, 1];
|
||||
|
||||
let bottom_node = tree.get(node_id).unwrap();
|
||||
for (i, node_ref) in bottom_node.ancestors().enumerate() {
|
||||
assert_eq!(node_ref.data(), &values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn children() {
|
||||
let mut tree = Tree::new();
|
||||
tree.set_root(1);
|
||||
|
||||
let mut root = tree.root_mut().expect("root doesn't exist");
|
||||
root.append(2);
|
||||
root.append(3);
|
||||
root.append(4);
|
||||
root.append(5);
|
||||
|
||||
let values = [2, 3, 4, 5];
|
||||
let root = root.as_ref();
|
||||
|
||||
for (i, node_ref) in root.children().enumerate() {
|
||||
assert_eq!(node_ref.data(), &values[i]);
|
||||
}
|
||||
}
|
||||
}
|
497
lib/slab-tree/src/slab.rs
Normal file
497
lib/slab-tree/src/slab.rs
Normal file
@ -0,0 +1,497 @@
|
||||
use std::mem;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||
pub(super) struct Index {
|
||||
index: usize,
|
||||
generation: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Slot<T> {
|
||||
Empty { next_free_slot: Option<usize> },
|
||||
Filled { item: T, generation: u64 },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(super) struct Slab<T> {
|
||||
data: Vec<Slot<T>>,
|
||||
first_free_slot: Option<usize>,
|
||||
generation: u64,
|
||||
}
|
||||
|
||||
impl<T> Slab<T> {
|
||||
pub(super) fn new(capacity: usize) -> Slab<T> {
|
||||
Slab {
|
||||
data: Vec::with_capacity(capacity),
|
||||
first_free_slot: None,
|
||||
generation: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn capacity(&self) -> usize {
|
||||
self.data.capacity()
|
||||
}
|
||||
|
||||
pub(super) fn insert(&mut self, item: T) -> Index {
|
||||
let new_slot = Slot::Filled {
|
||||
item,
|
||||
generation: self.generation,
|
||||
};
|
||||
|
||||
if let Some(index) = self.first_free_slot {
|
||||
match mem::replace(&mut self.data[index], new_slot) {
|
||||
Slot::Empty { next_free_slot } => {
|
||||
self.first_free_slot = next_free_slot;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Index {
|
||||
index,
|
||||
generation: self.generation,
|
||||
}
|
||||
} else {
|
||||
self.data.push(new_slot);
|
||||
Index {
|
||||
index: self.data.len() - 1,
|
||||
generation: self.generation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn remove(&mut self, index: Index) -> Option<T> {
|
||||
if index.index >= self.data.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let slot = mem::replace(
|
||||
&mut self.data[index.index],
|
||||
Slot::Empty {
|
||||
next_free_slot: self.first_free_slot,
|
||||
},
|
||||
);
|
||||
|
||||
match slot {
|
||||
Slot::Filled { item, generation } => {
|
||||
if index.generation == generation {
|
||||
self.generation += 1;
|
||||
self.first_free_slot = Some(index.index);
|
||||
Some(item)
|
||||
} else {
|
||||
self.data[index.index] = Slot::Filled { item, generation };
|
||||
None
|
||||
}
|
||||
}
|
||||
s => {
|
||||
self.data[index.index] = s;
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get(&self, index: Index) -> Option<&T> {
|
||||
self.data.get(index.index).and_then(|slot| match slot {
|
||||
Slot::Filled { item, generation } => {
|
||||
if index.generation == *generation {
|
||||
return Some(item);
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn get_mut(&mut self, index: Index) -> Option<&mut T> {
|
||||
self.data.get_mut(index.index).and_then(|slot| match slot {
|
||||
Slot::Filled { item, generation } => {
|
||||
if index.generation == *generation {
|
||||
return Some(item);
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn capacity() {
|
||||
let capacity = 5;
|
||||
let slab = Slab::<i32>::new(capacity);
|
||||
|
||||
assert_eq!(slab.capacity(), capacity);
|
||||
assert!(slab.first_free_slot.is_none());
|
||||
assert_eq!(slab.generation, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert() {
|
||||
let capacity = 2;
|
||||
let mut slab = Slab::new(capacity);
|
||||
|
||||
let six = slab.insert(6);
|
||||
|
||||
assert!(slab.first_free_slot.is_none());
|
||||
assert_eq!(slab.generation, 0);
|
||||
assert_eq!(slab.data.len(), 1);
|
||||
assert_eq!(slab.data.capacity(), capacity);
|
||||
|
||||
assert_eq!(six.generation, 0);
|
||||
assert_eq!(six.index, 0);
|
||||
|
||||
let seven = slab.insert(7);
|
||||
|
||||
assert!(slab.first_free_slot.is_none());
|
||||
assert_eq!(slab.generation, 0);
|
||||
assert_eq!(slab.data.len(), 2);
|
||||
assert_eq!(slab.data.capacity(), capacity);
|
||||
|
||||
assert_eq!(seven.generation, 0);
|
||||
assert_eq!(seven.index, 1);
|
||||
|
||||
let eight = slab.insert(8);
|
||||
|
||||
assert!(slab.first_free_slot.is_none());
|
||||
assert_eq!(slab.generation, 0);
|
||||
assert_eq!(slab.data.len(), 3);
|
||||
assert!(slab.data.capacity() >= capacity);
|
||||
|
||||
assert_eq!(eight.generation, 0);
|
||||
assert_eq!(eight.index, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_basic() {
|
||||
let mut slab = Slab::new(5);
|
||||
let _six = slab.insert(6);
|
||||
let seven = slab.insert(7);
|
||||
let _eight = slab.insert(8);
|
||||
// |6|7|8|
|
||||
|
||||
let seven_rem = slab.remove(seven);
|
||||
// |6|.|8|
|
||||
assert!(seven_rem.is_some());
|
||||
assert_eq!(seven_rem.unwrap(), 7);
|
||||
|
||||
assert_eq!(slab.first_free_slot.unwrap_or(10), 1);
|
||||
assert_eq!(slab.generation, 1);
|
||||
|
||||
let six_slot = slab.data.get(0);
|
||||
assert!(six_slot.is_some());
|
||||
|
||||
match six_slot.unwrap() {
|
||||
Slot::Empty { .. } => {
|
||||
panic!("Slot should be filled after call to insert.");
|
||||
}
|
||||
Slot::Filled { item, generation } => {
|
||||
assert_eq!(item, &6);
|
||||
assert_eq!(generation, &0);
|
||||
}
|
||||
}
|
||||
|
||||
let seven_slot = slab.data.get(1);
|
||||
assert!(seven_slot.is_some());
|
||||
|
||||
match seven_slot.unwrap() {
|
||||
Slot::Empty { next_free_slot } => {
|
||||
assert!(next_free_slot.is_none());
|
||||
}
|
||||
Slot::Filled { .. } => {
|
||||
panic!("Slot should be empty after call to remove.");
|
||||
}
|
||||
}
|
||||
|
||||
let eight_slot = slab.data.get(2);
|
||||
assert!(eight_slot.is_some());
|
||||
|
||||
match eight_slot.unwrap() {
|
||||
Slot::Empty { .. } => {
|
||||
panic!("Slot should be filled after call to insert.");
|
||||
}
|
||||
Slot::Filled { item, generation } => {
|
||||
assert_eq!(item, &8);
|
||||
assert_eq!(generation, &0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_remove() {
|
||||
let mut slab = Slab::new(5);
|
||||
let _six = slab.insert(6);
|
||||
let seven = slab.insert(7);
|
||||
let _eight = slab.insert(8);
|
||||
// |6|7|8|
|
||||
|
||||
let seven_rem = slab.remove(seven);
|
||||
// |6|.|8|
|
||||
assert!(seven_rem.is_some());
|
||||
assert_eq!(seven_rem.unwrap(), 7);
|
||||
|
||||
let seven_again = slab.remove(seven);
|
||||
assert!(seven_again.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_multiple() {
|
||||
let mut slab = Slab::new(5);
|
||||
let _six = slab.insert(6);
|
||||
let seven = slab.insert(7);
|
||||
let eight = slab.insert(8);
|
||||
// |6|7|8|
|
||||
|
||||
let seven_rem = slab.remove(seven);
|
||||
// |6|.|8|
|
||||
assert!(seven_rem.is_some());
|
||||
assert_eq!(seven_rem.unwrap(), 7);
|
||||
|
||||
assert_eq!(slab.first_free_slot.unwrap_or(10), 1);
|
||||
assert_eq!(slab.generation, 1);
|
||||
|
||||
let six_slot = slab.data.get(0);
|
||||
assert!(six_slot.is_some());
|
||||
|
||||
match six_slot.unwrap() {
|
||||
Slot::Empty { .. } => {
|
||||
panic!("Slot should be filled after call to insert.");
|
||||
}
|
||||
Slot::Filled { item, generation } => {
|
||||
assert_eq!(item, &6);
|
||||
assert_eq!(generation, &0);
|
||||
}
|
||||
}
|
||||
|
||||
let seven_slot = slab.data.get(1);
|
||||
assert!(seven_slot.is_some());
|
||||
|
||||
match seven_slot.unwrap() {
|
||||
Slot::Empty { next_free_slot } => {
|
||||
assert!(next_free_slot.is_none());
|
||||
}
|
||||
Slot::Filled { .. } => {
|
||||
panic!("Slot should be empty after call to remove.");
|
||||
}
|
||||
}
|
||||
|
||||
let eight_slot = slab.data.get(2);
|
||||
assert!(eight_slot.is_some());
|
||||
|
||||
match eight_slot.unwrap() {
|
||||
Slot::Empty { .. } => {
|
||||
panic!("Slot should be filled after call to insert.");
|
||||
}
|
||||
Slot::Filled { item, generation } => {
|
||||
assert_eq!(item, &8);
|
||||
assert_eq!(generation, &0);
|
||||
}
|
||||
}
|
||||
|
||||
let eight_rem = slab.remove(eight);
|
||||
// |6|.|.|
|
||||
assert!(eight_rem.is_some());
|
||||
assert_eq!(eight_rem.unwrap(), 8);
|
||||
|
||||
assert_eq!(slab.first_free_slot.unwrap_or(10), 2);
|
||||
assert_eq!(slab.generation, 2);
|
||||
|
||||
let six_slot = slab.data.get(0);
|
||||
assert!(six_slot.is_some());
|
||||
|
||||
match six_slot.unwrap() {
|
||||
Slot::Empty { .. } => {
|
||||
panic!("Slot should be filled after call to insert.");
|
||||
}
|
||||
Slot::Filled { item, generation } => {
|
||||
assert_eq!(item, &6);
|
||||
assert_eq!(generation, &0);
|
||||
}
|
||||
}
|
||||
|
||||
let seven_slot = slab.data.get(1);
|
||||
assert!(seven_slot.is_some());
|
||||
|
||||
match seven_slot.unwrap() {
|
||||
Slot::Empty { next_free_slot } => {
|
||||
assert!(next_free_slot.is_none());
|
||||
}
|
||||
Slot::Filled { .. } => {
|
||||
panic!("Slot should be empty after call to remove.");
|
||||
}
|
||||
}
|
||||
|
||||
let eight_slot = slab.data.get(2);
|
||||
assert!(eight_slot.is_some());
|
||||
|
||||
match eight_slot.unwrap() {
|
||||
Slot::Empty { next_free_slot } => {
|
||||
assert!(next_free_slot.is_some());
|
||||
assert_eq!(next_free_slot.unwrap(), 1);
|
||||
}
|
||||
Slot::Filled { .. } => {
|
||||
panic!("Slot should be empty after call to remove.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_and_reinsert() {
|
||||
let mut slab = Slab::new(5);
|
||||
let _six = slab.insert(6);
|
||||
let seven = slab.insert(7);
|
||||
let eight = slab.insert(8);
|
||||
// |6|7|8|
|
||||
|
||||
let seven_rem = slab.remove(seven);
|
||||
// |6|.|8|
|
||||
assert!(seven_rem.is_some());
|
||||
assert_eq!(seven_rem.unwrap(), 7);
|
||||
|
||||
assert_eq!(slab.first_free_slot.unwrap_or(10), 1);
|
||||
assert_eq!(slab.generation, 1);
|
||||
|
||||
let eight_rem = slab.remove(eight);
|
||||
// |6|.|.|
|
||||
assert!(eight_rem.is_some());
|
||||
assert_eq!(eight_rem.unwrap(), 8);
|
||||
|
||||
assert_eq!(slab.first_free_slot.unwrap_or(10), 2);
|
||||
assert_eq!(slab.generation, 2);
|
||||
|
||||
let nine = slab.insert(9);
|
||||
// |6|.|9|
|
||||
assert_eq!(nine.index, 2);
|
||||
assert_eq!(nine.generation, 2);
|
||||
|
||||
let eight_again = slab.remove(eight);
|
||||
assert!(eight_again.is_none());
|
||||
|
||||
let six_slot = slab.data.get(0);
|
||||
assert!(six_slot.is_some());
|
||||
|
||||
match six_slot.unwrap() {
|
||||
Slot::Empty { .. } => {
|
||||
panic!("Slot should be filled after call to insert.");
|
||||
}
|
||||
Slot::Filled { item, generation } => {
|
||||
assert_eq!(item, &6);
|
||||
assert_eq!(generation, &0);
|
||||
}
|
||||
}
|
||||
|
||||
let seven_slot = slab.data.get(1);
|
||||
assert!(seven_slot.is_some());
|
||||
|
||||
match seven_slot.unwrap() {
|
||||
Slot::Empty { next_free_slot } => {
|
||||
assert!(next_free_slot.is_none());
|
||||
}
|
||||
Slot::Filled { .. } => {
|
||||
panic!("Slot should be empty after call to remove.");
|
||||
}
|
||||
}
|
||||
|
||||
let nine_slot = slab.data.get(2);
|
||||
assert!(nine_slot.is_some());
|
||||
|
||||
match nine_slot.unwrap() {
|
||||
Slot::Empty { .. } => {
|
||||
panic!("Slot should be filled after call to insert.");
|
||||
}
|
||||
Slot::Filled { item, generation } => {
|
||||
assert_eq!(item, &9);
|
||||
assert_eq!(generation, &2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_with_bad_index() {
|
||||
let mut slab = Slab::new(5);
|
||||
let _six = slab.insert(6);
|
||||
let _seven = slab.insert(7);
|
||||
let mut eight = slab.insert(8);
|
||||
// |0|1|2| index
|
||||
// |6|7|8| value
|
||||
|
||||
eight.index = 3; // oops, this should be 2
|
||||
|
||||
let eight_rem = slab.remove(eight);
|
||||
assert!(eight_rem.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get() {
|
||||
let mut slab = Slab::new(5);
|
||||
|
||||
let six = slab.insert(6);
|
||||
assert_eq!(six.index, 0);
|
||||
assert_eq!(six.generation, 0);
|
||||
|
||||
let seven = slab.insert(7);
|
||||
assert_eq!(seven.index, 1);
|
||||
assert_eq!(seven.generation, 0);
|
||||
|
||||
let six_ref = slab.get(six);
|
||||
assert!(six_ref.is_some());
|
||||
assert_eq!(six_ref.unwrap(), &6);
|
||||
|
||||
slab.remove(six);
|
||||
|
||||
let six_ref = slab.get(six);
|
||||
assert!(six_ref.is_none());
|
||||
|
||||
let eight = slab.insert(8);
|
||||
assert_eq!(eight.index, 0);
|
||||
assert_eq!(eight.generation, 1);
|
||||
|
||||
let eight_ref = slab.get(eight);
|
||||
assert!(eight_ref.is_some());
|
||||
assert_eq!(eight_ref.unwrap(), &8);
|
||||
|
||||
let six_ref = slab.get(six);
|
||||
assert!(six_ref.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mut() {
|
||||
let mut slab = Slab::new(5);
|
||||
|
||||
let six = slab.insert(6);
|
||||
assert_eq!(six.index, 0);
|
||||
assert_eq!(six.generation, 0);
|
||||
|
||||
let seven = slab.insert(7);
|
||||
assert_eq!(seven.index, 1);
|
||||
assert_eq!(seven.generation, 0);
|
||||
|
||||
let six_mut = slab.get_mut(six);
|
||||
assert!(six_mut.is_some());
|
||||
|
||||
let six_mut = six_mut.unwrap();
|
||||
assert_eq!(six_mut, &mut 6);
|
||||
|
||||
*six_mut = 60;
|
||||
assert_eq!(six_mut, &mut 60);
|
||||
|
||||
slab.remove(six);
|
||||
|
||||
let six_ref = slab.get_mut(six);
|
||||
assert!(six_ref.is_none());
|
||||
|
||||
let eight = slab.insert(8);
|
||||
assert_eq!(eight.index, 0);
|
||||
assert_eq!(eight.generation, 1);
|
||||
|
||||
let eight_ref = slab.get_mut(eight);
|
||||
assert!(eight_ref.is_some());
|
||||
assert_eq!(eight_ref.unwrap(), &mut 8);
|
||||
|
||||
let six_ref = slab.get_mut(six);
|
||||
assert!(six_ref.is_none());
|
||||
}
|
||||
}
|
813
lib/slab-tree/src/tree.rs
Normal file
813
lib/slab-tree/src/tree.rs
Normal file
@ -0,0 +1,813 @@
|
||||
use crate::behaviors::*;
|
||||
use crate::core_tree::CoreTree;
|
||||
use crate::node::*;
|
||||
use crate::NodeId;
|
||||
|
||||
///
|
||||
/// A `Tree` builder. Provides more control over how a `Tree` is created.
|
||||
///
|
||||
pub struct TreeBuilder<T> {
|
||||
root: Option<T>,
|
||||
capacity: Option<usize>,
|
||||
}
|
||||
|
||||
impl<T> Default for TreeBuilder<T> {
|
||||
fn default() -> Self {
|
||||
TreeBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TreeBuilder<T> {
|
||||
///
|
||||
/// Creates a new `TreeBuilder` with the default settings.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let _tree_builder = TreeBuilder::new();
|
||||
///
|
||||
/// # _tree_builder.with_root(1);
|
||||
/// ```
|
||||
///
|
||||
pub fn new() -> TreeBuilder<T> {
|
||||
TreeBuilder {
|
||||
root: None,
|
||||
capacity: None,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Sets the root `Node` of the `TreeBuilder`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let _tree_builder = TreeBuilder::new().with_root(1);
|
||||
/// ```
|
||||
///
|
||||
pub fn with_root(self, root: T) -> TreeBuilder<T> {
|
||||
TreeBuilder {
|
||||
root: Some(root),
|
||||
capacity: self.capacity,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Sets the capacity of the `TreeBuilder`.
|
||||
///
|
||||
/// This can be used to pre-allocate space in the `Tree` if you know you'll be adding a large
|
||||
/// number of `Node`s to the `Tree`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let _tree_builder = TreeBuilder::new().with_capacity(10);
|
||||
///
|
||||
/// # _tree_builder.with_root(1);
|
||||
/// ```
|
||||
///
|
||||
pub fn with_capacity(self, capacity: usize) -> TreeBuilder<T> {
|
||||
TreeBuilder {
|
||||
root: self.root,
|
||||
capacity: Some(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Build a `Tree` based upon the current settings in the `TreeBuilder`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let _tree = TreeBuilder::new().with_root(1).with_capacity(10).build();
|
||||
/// ```
|
||||
///
|
||||
pub fn build(self) -> Tree<T> {
|
||||
let capacity = self.capacity.unwrap_or(0);
|
||||
let mut core_tree: CoreTree<T> = CoreTree::new(capacity);
|
||||
let root_id = self.root.map(|val| core_tree.insert(val));
|
||||
|
||||
Tree { root_id, core_tree }
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// A tree structure containing `Node`s.
|
||||
///
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Tree<T> {
|
||||
pub(crate) root_id: Option<NodeId>,
|
||||
pub(crate) core_tree: CoreTree<T>,
|
||||
}
|
||||
|
||||
impl<T> Tree<T> {
|
||||
///
|
||||
/// Creates a new `Tree` with a capacity of 0.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::Tree;
|
||||
///
|
||||
/// let tree: Tree<i32> = Tree::new();
|
||||
///
|
||||
/// # assert_eq!(tree.capacity(), 0);
|
||||
/// ```
|
||||
///
|
||||
pub fn new() -> Tree<T> {
|
||||
TreeBuilder::new().build()
|
||||
}
|
||||
|
||||
//todo: write test for this
|
||||
///
|
||||
/// Sets the "root" of the `Tree` to be `root`.
|
||||
///
|
||||
/// If there is already a "root" node in the `Tree`, that node is shifted down and the new
|
||||
/// one takes its place.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::Tree;
|
||||
///
|
||||
/// let mut tree = Tree::new();
|
||||
///
|
||||
/// let root_id = tree.set_root(1);
|
||||
///
|
||||
/// assert_eq!(tree.root_id().unwrap(), root_id);
|
||||
/// ```
|
||||
///
|
||||
pub fn set_root(&mut self, root: T) -> NodeId {
|
||||
let old_root_id = self.root_id.take();
|
||||
let new_root_id = self.core_tree.insert(root);
|
||||
|
||||
self.root_id = Some(new_root_id);
|
||||
|
||||
self.set_first_child(new_root_id, old_root_id);
|
||||
self.set_last_child(new_root_id, old_root_id);
|
||||
|
||||
if let Some(node_id) = old_root_id {
|
||||
self.set_parent(node_id, self.root_id);
|
||||
}
|
||||
|
||||
new_root_id
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the `Tree`'s current capacity. Capacity is defined as the number of times new
|
||||
/// `Node`s can be added to the `Tree` before it must allocate more memory.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::Tree;
|
||||
///
|
||||
/// let tree: Tree<i32> = Tree::new();
|
||||
///
|
||||
/// assert_eq!(tree.capacity(), 0);
|
||||
/// ```
|
||||
///
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.core_tree.capacity()
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the `NodeId` of the root node of the `Tree`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::Tree;
|
||||
///
|
||||
/// let mut tree = Tree::new();
|
||||
/// tree.set_root(1);
|
||||
///
|
||||
/// let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
///
|
||||
/// assert_eq!(tree.get(root_id).unwrap().data(), &1);
|
||||
/// ```
|
||||
///
|
||||
pub fn root_id(&self) -> Option<NodeId> {
|
||||
self.root_id
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `NodeRef` pointing to the root `Node` of the `Tree`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::Tree;
|
||||
///
|
||||
/// let mut tree = Tree::new();
|
||||
/// tree.set_root(1);
|
||||
///
|
||||
/// let root = tree.root().expect("root doesn't exist?");
|
||||
///
|
||||
/// assert_eq!(root.data(), &1);
|
||||
/// ```
|
||||
///
|
||||
pub fn root(&self) -> Option<NodeRef<T>> {
|
||||
self.root_id.map(|id| self.new_node_ref(id))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `NodeMut` pointing to the root `Node` of the `Tree`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::Tree;
|
||||
///
|
||||
/// let mut tree = Tree::new();
|
||||
/// tree.set_root(1);
|
||||
///
|
||||
/// let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||
/// assert_eq!(root.data(), &mut 1);
|
||||
///
|
||||
/// *root.data() = 2;
|
||||
/// assert_eq!(root.data(), &mut 2);
|
||||
/// ```
|
||||
///
|
||||
pub fn root_mut(&mut self) -> Option<NodeMut<T>> {
|
||||
self.root_id.map(move |id| self.new_node_mut(id))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the `NodeRef` pointing to the `Node` that the given `NodeId` identifies. If the
|
||||
/// `NodeId` in question points to nothing (or belongs to a different `Tree`) a `None`-value
|
||||
/// will be returned; otherwise, a `Some`-value will be returned.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::Tree;
|
||||
///
|
||||
/// let mut tree = Tree::new();
|
||||
/// tree.set_root(1);
|
||||
/// let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
///
|
||||
/// let root = tree.get(root_id);
|
||||
/// assert!(root.is_some());
|
||||
///
|
||||
/// let root = root.unwrap();
|
||||
/// assert_eq!(root.data(), &1);
|
||||
/// ```
|
||||
///
|
||||
pub fn get(&self, node_id: NodeId) -> Option<NodeRef<T>> {
|
||||
let _ = self.core_tree.get(node_id)?;
|
||||
Some(self.new_node_ref(node_id))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the `NodeMut` pointing to the `Node` that the given `NodeId` identifies. If the
|
||||
/// `NodeId` in question points to nothing (or belongs to a different `Tree`) a `None`-value
|
||||
/// will be returned; otherwise, a `Some`-value will be returned.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::Tree;
|
||||
///
|
||||
/// let mut tree = Tree::new();
|
||||
/// tree.set_root(1);
|
||||
/// let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
///
|
||||
/// let root = tree.get_mut(root_id);
|
||||
/// assert!(root.is_some());
|
||||
///
|
||||
/// let mut root = root.unwrap();
|
||||
///
|
||||
/// *root.data() = 2;
|
||||
/// assert_eq!(root.data(), &mut 2);
|
||||
/// ```
|
||||
///
|
||||
pub fn get_mut(&mut self, node_id: NodeId) -> Option<NodeMut<T>> {
|
||||
let _ = self.core_tree.get_mut(node_id)?;
|
||||
Some(self.new_node_mut(node_id))
|
||||
}
|
||||
|
||||
///
|
||||
/// Remove a `Node` by its `NodeId` and return the data that it contained.
|
||||
/// Returns a `Some`-value if the `Node` exists; returns a `None`-value otherwise.
|
||||
///
|
||||
/// Children of the removed `Node` can either be dropped with `DropChildren` or orphaned with
|
||||
/// `OrphanChildren`.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
/// use slab_tree::behaviors::RemoveBehavior::*;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
/// let two_id = {
|
||||
/// let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||
/// let two_id = root.append(2).node_id();
|
||||
/// root.append(3);
|
||||
/// two_id
|
||||
/// };
|
||||
///
|
||||
/// let two = tree.remove(two_id, DropChildren);
|
||||
///
|
||||
/// assert!(two.is_some());
|
||||
/// assert_eq!(two.unwrap(), 2);
|
||||
///
|
||||
/// let root = tree.root().expect("root doesn't exist?");
|
||||
/// assert!(root.first_child().is_some());
|
||||
/// assert_eq!(root.first_child().unwrap().data(), &mut 3);
|
||||
///
|
||||
/// assert!(root.last_child().is_some());
|
||||
/// assert_eq!(root.last_child().unwrap().data(), &mut 3);
|
||||
/// ```
|
||||
///
|
||||
pub fn remove(&mut self, node_id: NodeId, behavior: RemoveBehavior) -> Option<T> {
|
||||
if let Some(node) = self.get_node(node_id) {
|
||||
let Relatives {
|
||||
parent,
|
||||
prev_sibling,
|
||||
next_sibling,
|
||||
..
|
||||
} = node.relatives;
|
||||
|
||||
let (is_first_child, is_last_child) = self.is_node_first_last_child(node_id);
|
||||
|
||||
if is_first_child {
|
||||
// parent first child = my next sibling
|
||||
self.set_first_child(parent.expect("parent must exist"), next_sibling);
|
||||
}
|
||||
if is_last_child {
|
||||
// parent last child = my prev sibling
|
||||
self.set_last_child(parent.expect("parent must exist"), prev_sibling);
|
||||
}
|
||||
if let Some(prev) = prev_sibling {
|
||||
self.set_next_sibling(prev, next_sibling);
|
||||
}
|
||||
if let Some(next) = next_sibling {
|
||||
self.set_prev_sibling(next, prev_sibling);
|
||||
}
|
||||
|
||||
match behavior {
|
||||
RemoveBehavior::DropChildren => self.drop_children(node_id),
|
||||
RemoveBehavior::OrphanChildren => self.orphan_children(node_id),
|
||||
};
|
||||
if self.root_id == Some(node_id) {
|
||||
self.root_id = None;
|
||||
}
|
||||
self.core_tree.remove(node_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_node(&self, node_id: NodeId) -> Option<&Node<T>> {
|
||||
self.core_tree.get(node_id)
|
||||
}
|
||||
|
||||
pub(crate) fn get_node_mut(&mut self, node_id: NodeId) -> Option<&mut Node<T>> {
|
||||
self.core_tree.get_mut(node_id)
|
||||
}
|
||||
|
||||
pub(crate) fn set_prev_siblings_next_sibling(
|
||||
&mut self,
|
||||
current_id: NodeId,
|
||||
next_sibling: Option<NodeId>,
|
||||
) {
|
||||
if let Some(prev_sibling_id) = self.get_node_prev_sibling_id(current_id) {
|
||||
self.set_next_sibling(prev_sibling_id, next_sibling);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_next_siblings_prev_sibling(
|
||||
&mut self,
|
||||
current_id: NodeId,
|
||||
prev_sibling: Option<NodeId>,
|
||||
) {
|
||||
if let Some(next_sibling_id) = self.get_node_next_sibling_id(current_id) {
|
||||
self.set_prev_sibling(next_sibling_id, prev_sibling);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_parent(&mut self, node_id: NodeId, parent_id: Option<NodeId>) {
|
||||
if let Some(node) = self.get_node_mut(node_id) {
|
||||
node.relatives.parent = parent_id;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_prev_sibling(&mut self, node_id: NodeId, prev_sibling: Option<NodeId>) {
|
||||
if let Some(node) = self.get_node_mut(node_id) {
|
||||
node.relatives.prev_sibling = prev_sibling;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_next_sibling(&mut self, node_id: NodeId, next_sibling: Option<NodeId>) {
|
||||
if let Some(node) = self.get_node_mut(node_id) {
|
||||
node.relatives.next_sibling = next_sibling;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_first_child(&mut self, node_id: NodeId, first_child: Option<NodeId>) {
|
||||
if let Some(node) = self.get_node_mut(node_id) {
|
||||
node.relatives.first_child = first_child;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_last_child(&mut self, node_id: NodeId, last_child: Option<NodeId>) {
|
||||
if let Some(node) = self.get_node_mut(node_id) {
|
||||
node.relatives.last_child = last_child;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_node_prev_sibling_id(&self, node_id: NodeId) -> Option<NodeId> {
|
||||
if let Some(node) = self.get_node(node_id) {
|
||||
node.relatives.prev_sibling
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_node_next_sibling_id(&self, node_id: NodeId) -> Option<NodeId> {
|
||||
if let Some(node) = self.get_node(node_id) {
|
||||
node.relatives.next_sibling
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_node_relatives(&self, node_id: NodeId) -> Relatives {
|
||||
if let Some(node) = self.get_node(node_id) {
|
||||
node.relatives
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_children(&mut self, node_id: NodeId) {
|
||||
let sub_tree_ids: Vec<NodeId> = self
|
||||
.get(node_id)
|
||||
.expect("node must exist")
|
||||
.traverse_level_order()
|
||||
.skip(1) // skip the "root" of the sub-tree, which is the "current" node
|
||||
.map(|node_ref| node_ref.node_id())
|
||||
.collect();
|
||||
|
||||
for id in sub_tree_ids {
|
||||
self.core_tree.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
fn orphan_children(&mut self, node_id: NodeId) {
|
||||
let child_ids: Vec<NodeId> = self
|
||||
.get(node_id)
|
||||
.expect("node must exist")
|
||||
.children()
|
||||
.map(|node_ref| node_ref.node_id())
|
||||
.collect();
|
||||
|
||||
for id in child_ids {
|
||||
self.set_parent(id, None);
|
||||
}
|
||||
}
|
||||
|
||||
fn new_node_ref(&self, node_id: NodeId) -> NodeRef<T> {
|
||||
NodeRef::new(node_id, self)
|
||||
}
|
||||
|
||||
fn new_node_mut(&mut self, node_id: NodeId) -> NodeMut<T> {
|
||||
NodeMut::new(node_id, self)
|
||||
}
|
||||
|
||||
fn is_node_first_last_child(&self, node_id: NodeId) -> (bool, bool) {
|
||||
if let Some(node) = self.get_node(node_id) {
|
||||
node.relatives
|
||||
.parent
|
||||
.and_then(|parent_id| self.get_node(parent_id))
|
||||
.map(|parent| {
|
||||
let Relatives {
|
||||
first_child: first,
|
||||
last_child: last,
|
||||
..
|
||||
} = parent.relatives;
|
||||
(
|
||||
first.map(|child_id| child_id == node_id).unwrap_or(false),
|
||||
last.map(|child_id| child_id == node_id).unwrap_or(false),
|
||||
)
|
||||
})
|
||||
.unwrap_or((false, false))
|
||||
} else {
|
||||
(false, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Tree<T> {
|
||||
fn default() -> Self {
|
||||
TreeBuilder::new().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::fmt::Debug> Tree<T> {
|
||||
/// Write formatted tree representation and nodes with debug formatting.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let mut tree = TreeBuilder::new().with_root(0).build();
|
||||
/// let mut root = tree.root_mut().unwrap();
|
||||
/// root.append(1)
|
||||
/// .append(2);
|
||||
/// root.append(3);
|
||||
/// let mut s = String::new();
|
||||
/// tree.write_formatted(&mut s).unwrap();
|
||||
/// assert_eq!(&s, "\
|
||||
/// 0
|
||||
/// ├── 1
|
||||
/// │ └── 2
|
||||
/// └── 3
|
||||
/// ");
|
||||
/// ```
|
||||
///
|
||||
/// Writes nothing if the tree is empty.
|
||||
///
|
||||
/// ```
|
||||
/// use slab_tree::tree::TreeBuilder;
|
||||
///
|
||||
/// let tree = TreeBuilder::<i32>::new().build();
|
||||
/// let mut s = String::new();
|
||||
/// tree.write_formatted(&mut s).unwrap();
|
||||
/// assert_eq!(&s, "");
|
||||
/// ```
|
||||
pub fn write_formatted<W: std::fmt::Write>(&self, w: &mut W) -> std::fmt::Result {
|
||||
if let Some(root) = self.root() {
|
||||
let node_id = root.node_id();
|
||||
let childn = 0;
|
||||
let level = 0;
|
||||
let last = vec![];
|
||||
let mut stack = vec![(node_id, childn, level, last)];
|
||||
while let Some((node_id, childn, level, last)) = stack.pop() {
|
||||
debug_assert_eq!(
|
||||
last.len(),
|
||||
level,
|
||||
"each previous level should indicate whether it has reached the last node"
|
||||
);
|
||||
let node = self
|
||||
.get(node_id)
|
||||
.expect("getting node of existing node ref id");
|
||||
if childn == 0 {
|
||||
for i in 1..level {
|
||||
if last[i - 1] {
|
||||
write!(w, " ")?;
|
||||
} else {
|
||||
write!(w, "│ ")?;
|
||||
}
|
||||
}
|
||||
if level > 0 {
|
||||
if last[level - 1] {
|
||||
write!(w, "└── ")?;
|
||||
} else {
|
||||
write!(w, "├── ")?;
|
||||
}
|
||||
}
|
||||
writeln!(w, "{:?}", node.data())?;
|
||||
}
|
||||
let mut children = node.children().skip(childn);
|
||||
if let Some(child) = children.next() {
|
||||
let mut next_last = last.clone();
|
||||
if children.next().is_some() {
|
||||
stack.push((node_id, childn + 1, level, last));
|
||||
next_last.push(false);
|
||||
} else {
|
||||
next_last.push(true);
|
||||
}
|
||||
stack.push((child.node_id(), 0, level + 1, next_last));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
#[cfg(test)]
|
||||
mod tree_tests {
|
||||
use super::*;
|
||||
use crate::behaviors::RemoveBehavior::{DropChildren, OrphanChildren};
|
||||
|
||||
#[test]
|
||||
fn capacity() {
|
||||
let tree = TreeBuilder::new().with_root(1).with_capacity(5).build();
|
||||
assert_eq!(tree.capacity(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn root_id() {
|
||||
let tree = TreeBuilder::new().with_root(1).build();
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root = tree.get(root_id).unwrap();
|
||||
assert_eq!(root.data(), &1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_root_drop() {
|
||||
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
|
||||
tree.remove(root_id, RemoveBehavior::DropChildren);
|
||||
assert!(tree.root().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_root_orphan() {
|
||||
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
|
||||
tree.remove(root_id, RemoveBehavior::OrphanChildren);
|
||||
assert!(tree.root().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn root() {
|
||||
let tree = TreeBuilder::new().with_root(1).build();
|
||||
let root = tree.root().expect("root doesn't exist?");
|
||||
assert_eq!(root.data(), &1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn root_mut() {
|
||||
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||
|
||||
assert_eq!(root.data(), &mut 1);
|
||||
|
||||
*root.data() = 2;
|
||||
assert_eq!(root.data(), &mut 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get() {
|
||||
let tree = TreeBuilder::new().with_root(1).build();
|
||||
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root = tree.get(root_id);
|
||||
assert!(root.is_some());
|
||||
|
||||
let root = root.unwrap();
|
||||
assert_eq!(root.data(), &1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mut() {
|
||||
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root = tree.get_mut(root_id);
|
||||
assert!(root.is_some());
|
||||
|
||||
let mut root = root.unwrap();
|
||||
assert_eq!(root.data(), &mut 1);
|
||||
|
||||
*root.data() = 2;
|
||||
assert_eq!(root.data(), &mut 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_node() {
|
||||
let tree = TreeBuilder::new().with_root(1).build();
|
||||
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root = tree.get_node(root_id);
|
||||
assert!(root.is_some());
|
||||
|
||||
let root = root.unwrap();
|
||||
assert_eq!(root.data, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_node_mut() {
|
||||
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
|
||||
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||
let root = tree.get_node_mut(root_id);
|
||||
assert!(root.is_some());
|
||||
|
||||
let root = root.unwrap();
|
||||
assert_eq!(root.data, 1);
|
||||
|
||||
root.data = 2;
|
||||
assert_eq!(root.data, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_drop() {
|
||||
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
|
||||
let two_id;
|
||||
let three_id;
|
||||
let four_id;
|
||||
let five_id;
|
||||
{
|
||||
let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||
two_id = root.append(2).node_id();
|
||||
three_id = root.append(3).node_id();
|
||||
four_id = root.append(4).node_id();
|
||||
}
|
||||
{
|
||||
five_id = tree
|
||||
.get_mut(three_id)
|
||||
.expect("three doesn't exist?")
|
||||
.append(5)
|
||||
.node_id();
|
||||
}
|
||||
|
||||
// 1
|
||||
// / | \
|
||||
// 2 3 4
|
||||
// |
|
||||
// 5
|
||||
|
||||
tree.remove(three_id, DropChildren);
|
||||
|
||||
let root = tree
|
||||
.get_node(tree.root_id().expect("tree doesn't exist?"))
|
||||
.unwrap();
|
||||
assert!(root.relatives.first_child.is_some());
|
||||
assert!(root.relatives.last_child.is_some());
|
||||
assert_eq!(root.relatives.first_child.unwrap(), two_id);
|
||||
assert_eq!(root.relatives.last_child.unwrap(), four_id);
|
||||
|
||||
let two = tree.get_node(two_id);
|
||||
assert!(two.is_some());
|
||||
|
||||
let two = two.unwrap();
|
||||
assert_eq!(two.relatives.next_sibling, Some(four_id));
|
||||
|
||||
let four = tree.get_node(four_id);
|
||||
assert!(four.is_some());
|
||||
|
||||
let four = four.unwrap();
|
||||
assert_eq!(four.relatives.prev_sibling, Some(two_id));
|
||||
|
||||
let five = tree.get_node(five_id);
|
||||
assert!(five.is_none());
|
||||
}
|
||||
|
||||
/// Test that there is no panic if caller tries to remove a removed node
|
||||
#[test]
|
||||
fn address_dropped() {
|
||||
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
let two_id = tree.root_mut().expect("root doesn't exist").node_id();
|
||||
tree.remove(two_id, DropChildren);
|
||||
tree.remove(two_id, DropChildren);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_orphan() {
|
||||
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||
|
||||
let two_id;
|
||||
let three_id;
|
||||
let four_id;
|
||||
let five_id;
|
||||
{
|
||||
let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||
two_id = root.append(2).node_id();
|
||||
three_id = root.append(3).node_id();
|
||||
four_id = root.append(4).node_id();
|
||||
}
|
||||
{
|
||||
five_id = tree
|
||||
.get_mut(three_id)
|
||||
.expect("three doesn't exist?")
|
||||
.append(5)
|
||||
.node_id();
|
||||
}
|
||||
|
||||
// 1
|
||||
// / | \
|
||||
// 2 3 4
|
||||
// |
|
||||
// 5
|
||||
|
||||
tree.remove(three_id, OrphanChildren);
|
||||
|
||||
let root = tree
|
||||
.get_node(tree.root_id().expect("tree doesn't exist?"))
|
||||
.unwrap();
|
||||
assert!(root.relatives.first_child.is_some());
|
||||
assert!(root.relatives.last_child.is_some());
|
||||
assert_eq!(root.relatives.first_child.unwrap(), two_id);
|
||||
assert_eq!(root.relatives.last_child.unwrap(), four_id);
|
||||
|
||||
let two = tree.get_node(two_id);
|
||||
assert!(two.is_some());
|
||||
|
||||
let two = two.unwrap();
|
||||
assert_eq!(two.relatives.next_sibling, Some(four_id));
|
||||
|
||||
let four = tree.get_node(four_id);
|
||||
assert!(four.is_some());
|
||||
|
||||
let four = four.unwrap();
|
||||
assert_eq!(four.relatives.prev_sibling, Some(two_id));
|
||||
|
||||
let five = tree.get_node(five_id);
|
||||
assert!(five.is_some());
|
||||
|
||||
let five = five.unwrap();
|
||||
assert_eq!(five.relatives.parent, None);
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ use std::{fs, io};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use ratatui::style::Color;
|
||||
|
||||
use slab_tree::NodeId;
|
||||
|
||||
use crate::component::dialog::input::InputFieldDialogLayer;
|
||||
@ -11,7 +12,6 @@ use crate::component::filesystem::FsLayer;
|
||||
use crate::file::FileKind;
|
||||
use crate::state::action::{Action, ActionResult};
|
||||
use crate::state::Environment;
|
||||
use crate::util::slab_tree::NodeRefExtensions;
|
||||
|
||||
trait CreateEntry {
|
||||
fn title() -> &'static str;
|
||||
|
@ -13,7 +13,6 @@ use crate::component::filesystem::tree::FsTreeViewNode;
|
||||
use crate::state::action::{Action, ActionResult};
|
||||
use crate::state::Environment;
|
||||
use crate::state::event::EventResult;
|
||||
use crate::util::slab_tree::NodeRefExtensions;
|
||||
|
||||
pub struct EditSelectedEntry;
|
||||
|
||||
|
@ -3,6 +3,7 @@ use std::{fs, io};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use ratatui::style::Color;
|
||||
|
||||
use slab_tree::NodeRef;
|
||||
|
||||
use crate::component::dialog::input::InputFieldDialogLayer;
|
||||
@ -13,7 +14,6 @@ use crate::component::filesystem::tree::FsTreeViewNode;
|
||||
use crate::file::FileEntry;
|
||||
use crate::state::action::{Action, ActionResult};
|
||||
use crate::state::Environment;
|
||||
use crate::util::slab_tree::NodeRefExtensions;
|
||||
|
||||
pub struct RenameSelectedEntry {
|
||||
pub prefill: bool,
|
||||
|
@ -2,14 +2,13 @@ use slab_tree::{NodeId, NodeRef};
|
||||
|
||||
use crate::component::filesystem::action::movement::{MovementAction, perform_movement_with_count_from_register, SimpleMovementAction};
|
||||
use crate::component::filesystem::FsLayer;
|
||||
use crate::component::filesystem::tree::{FsTree, FsTreeView, FsTreeViewNode};
|
||||
use crate::component::filesystem::tree::{FsTree, FsTreeViewNode};
|
||||
use crate::state::Environment;
|
||||
use crate::util::slab_tree::NodeRefExtensions;
|
||||
|
||||
pub struct MoveToNextSibling;
|
||||
|
||||
impl SimpleMovementAction for MoveToNextSibling {
|
||||
fn get_target(_view: &FsTreeView, selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
fn get_target(selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
selected_node.next_sibling_id()
|
||||
}
|
||||
}
|
||||
@ -17,7 +16,7 @@ impl SimpleMovementAction for MoveToNextSibling {
|
||||
pub struct MoveToPreviousSibling;
|
||||
|
||||
impl SimpleMovementAction for MoveToPreviousSibling {
|
||||
fn get_target(_view: &FsTreeView, selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
fn get_target(selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
selected_node.prev_sibling_id()
|
||||
}
|
||||
}
|
||||
@ -25,7 +24,7 @@ impl SimpleMovementAction for MoveToPreviousSibling {
|
||||
pub struct MoveBetweenFirstAndLastSibling;
|
||||
|
||||
impl SimpleMovementAction for MoveBetweenFirstAndLastSibling {
|
||||
fn get_target(_view: &FsTreeView, selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
fn get_target(selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
if selected_node.next_sibling().is_none() {
|
||||
selected_node.parent().and_then(|node| node.first_child_id())
|
||||
} else {
|
||||
@ -37,7 +36,7 @@ impl SimpleMovementAction for MoveBetweenFirstAndLastSibling {
|
||||
pub struct MoveToParent;
|
||||
|
||||
impl SimpleMovementAction for MoveToParent {
|
||||
fn get_target(_view: &FsTreeView, selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
fn get_target(selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
selected_node.parent_id()
|
||||
}
|
||||
}
|
||||
@ -52,8 +51,8 @@ impl MovementAction for MoveOrTraverseUpParent {
|
||||
|
||||
impl MoveOrTraverseUpParent {
|
||||
fn get_target(tree: &mut FsTree, node_id: NodeId) -> Option<NodeId> {
|
||||
if let Some(node) = tree.view.get(node_id) {
|
||||
let target_node_id = <MoveToParent as SimpleMovementAction>::get_target(&tree.view, &node);
|
||||
if let Some(node) = tree.get_view_node(node_id) {
|
||||
let target_node_id = <MoveToParent as SimpleMovementAction>::get_target(&node);
|
||||
if target_node_id.is_some() {
|
||||
return target_node_id;
|
||||
} else if let Some(target_node_id) = tree.traverse_up_root() {
|
||||
|
@ -2,15 +2,15 @@ use slab_tree::{NodeId, NodeRef};
|
||||
|
||||
use crate::component::filesystem::action::movement::{get_simple_movement_target, MovementAction, MoveToParent, perform_movement_with_count_from, SimpleMovementAction};
|
||||
use crate::component::filesystem::FsLayer;
|
||||
use crate::component::filesystem::tree::{FsTree, FsTreeView, FsTreeViewNode};
|
||||
use crate::component::filesystem::tree::{FsTree, FsTreeViewNode};
|
||||
use crate::state::Environment;
|
||||
|
||||
/// Moves up `count` lines (1 line by default).
|
||||
pub struct MoveUp;
|
||||
|
||||
impl SimpleMovementAction for MoveUp {
|
||||
fn get_target(tree: &FsTreeView, selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
tree.get_node_above(selected_node)
|
||||
fn get_target(selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
selected_node.above_id()
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,8 +18,8 @@ impl SimpleMovementAction for MoveUp {
|
||||
pub struct MoveDown;
|
||||
|
||||
impl SimpleMovementAction for MoveDown {
|
||||
fn get_target(tree: &FsTreeView, selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> {
|
||||
tree.get_node_below(selected_node)
|
||||
fn get_target(selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> {
|
||||
selected_node.below_id()
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ impl MoveToFirst {
|
||||
fn get_target(tree: &mut FsTree) -> NodeId where Self: Sized {
|
||||
let mut target_node_id = tree.selected_view_node_id;
|
||||
|
||||
while let Some(node_id) = tree.view.get(target_node_id).and_then(|node| <MoveToParent as SimpleMovementAction>::get_target(&tree.view, &node)) {
|
||||
while let Some(node_id) = tree.get_view_node(target_node_id).and_then(|node| <MoveToParent as SimpleMovementAction>::get_target(&node)) {
|
||||
target_node_id = node_id;
|
||||
}
|
||||
|
||||
@ -50,8 +50,8 @@ pub struct MoveToLast;
|
||||
impl MovementAction for MoveToLast {
|
||||
fn get_target(&self, layer: &mut FsLayer, _environment: &Environment) -> Option<NodeId> where Self: Sized {
|
||||
let first_node_id = MoveToFirst::get_target(&mut layer.tree);
|
||||
let last_node_id = layer.tree.view.get_last_descendant_or_self(first_node_id);
|
||||
Some(last_node_id)
|
||||
let last_node_id = layer.tree.get_view_node(first_node_id).map(|node| node.last_descendant_or_self().node_id());
|
||||
last_node_id
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use slab_tree::{NodeId, NodeRef};
|
||||
|
||||
use crate::component::filesystem::FsLayer;
|
||||
use crate::component::filesystem::tree::{FsTree, FsTreeView, FsTreeViewNode};
|
||||
use crate::component::filesystem::tree::{FsTree, FsTreeViewNode};
|
||||
use crate::state::action::{Action, ActionResult};
|
||||
use crate::state::Environment;
|
||||
|
||||
@ -56,7 +56,7 @@ fn perform_movement_with_count_from<F>(tree: &mut FsTree, count: Option<usize>,
|
||||
}
|
||||
|
||||
pub trait SimpleMovementAction {
|
||||
fn get_target(view: &FsTreeView, selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized;
|
||||
fn get_target(selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized;
|
||||
}
|
||||
|
||||
impl<T: SimpleMovementAction> MovementAction for T {
|
||||
@ -66,5 +66,5 @@ impl<T: SimpleMovementAction> MovementAction for T {
|
||||
}
|
||||
|
||||
fn get_simple_movement_target<T: SimpleMovementAction>(tree: &mut FsTree, node_id: NodeId) -> Option<NodeId> {
|
||||
tree.view.get(node_id).and_then(|node| T::get_target(&tree.view, &node))
|
||||
tree.get_view_node(node_id).and_then(|node| T::get_target(&node))
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
||||
use slab_tree::{NodeId, NodeRef};
|
||||
|
||||
use crate::component::filesystem::action::movement::SimpleMovementAction;
|
||||
use crate::component::filesystem::tree::{FsTreeView, FsTreeViewNode};
|
||||
use crate::component::filesystem::tree::FsTreeViewNode;
|
||||
|
||||
/// A movement action with fallback.
|
||||
pub struct MovementWithFallback<A: SimpleMovementAction, F: SimpleMovementAction>(PhantomData<A>, PhantomData<F>);
|
||||
@ -21,7 +21,7 @@ impl<A: SimpleMovementAction, F: SimpleMovementAction> MovementWithFallbackFacto
|
||||
}
|
||||
|
||||
impl<A: SimpleMovementAction, F: SimpleMovementAction> SimpleMovementAction for MovementWithFallback<A, F> {
|
||||
fn get_target(view: &FsTreeView, selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
A::get_target(view, selected_node).or_else(|| F::get_target(view, selected_node))
|
||||
fn get_target(selected_node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> where Self: Sized {
|
||||
A::get_target(selected_node).or_else(|| F::get_target(selected_node))
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use ratatui::widgets::{Clear, Widget};
|
||||
use slab_tree::{NodeId, NodeRef};
|
||||
|
||||
use crate::component::filesystem::{ColumnWidths, FsLayer};
|
||||
use crate::component::filesystem::tree::{FsTree, FsTreeView, FsTreeViewNode};
|
||||
use crate::component::filesystem::tree::{FsTree, FsTreeViewNode};
|
||||
use crate::file::{FileEntry, FileKind, FileOwnerNameCache};
|
||||
use crate::state::view::Frame;
|
||||
|
||||
@ -37,7 +37,7 @@ fn get_or_update_column_widths(layer: &mut FsLayer, cols: u16) -> ColumnWidths {
|
||||
let mut user: usize = 0;
|
||||
let mut group: usize = 0;
|
||||
|
||||
for node in &layer.tree.view {
|
||||
for node in layer.tree.view_iter() {
|
||||
let entry = layer.tree.get_entry(&node).unwrap_or_else(|| FileEntry::dummy_as_ref());
|
||||
|
||||
name = max(name, get_node_level(&node).saturating_add(Span::from(entry.name().str()).width()));
|
||||
@ -63,7 +63,7 @@ fn collect_displayed_rows(tree: &FsTree, selected_node_id: NodeId, terminal_rows
|
||||
let mut displayed_rows = Vec::with_capacity(terminal_rows);
|
||||
let mut cursor_y: u16 = 0;
|
||||
|
||||
if let Some(middle_node) = tree.selected_node().or_else(|| tree.view.root()) {
|
||||
if let Some(middle_node) = tree.selected_node().or_else(|| tree.view_root_node()) {
|
||||
let middle_node_id = middle_node.node_id();
|
||||
|
||||
displayed_rows.push(NodeRow::from(&middle_node, tree, middle_node_id == selected_node_id));
|
||||
@ -72,7 +72,7 @@ fn collect_displayed_rows(tree: &FsTree, selected_node_id: NodeId, terminal_rows
|
||||
let mut cursor_down_id = Some(middle_node_id);
|
||||
|
||||
while displayed_rows.len() < terminal_rows {
|
||||
if let Some(next_node_up) = move_cursor(tree, &mut cursor_up_id, FsTreeView::get_node_above) {
|
||||
if let Some(next_node_up) = move_cursor(tree, &mut cursor_up_id, |node| node.above_id()) {
|
||||
displayed_rows.insert(0, NodeRow::from(&next_node_up, tree, false));
|
||||
cursor_y = cursor_y.saturating_add(1);
|
||||
}
|
||||
@ -81,7 +81,7 @@ fn collect_displayed_rows(tree: &FsTree, selected_node_id: NodeId, terminal_rows
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(next_node_down) = move_cursor(tree, &mut cursor_down_id, FsTreeView::get_node_below) {
|
||||
if let Some(next_node_down) = move_cursor(tree, &mut cursor_down_id, |node| node.below_id()) {
|
||||
displayed_rows.push(NodeRow::from(&next_node_down, tree, false));
|
||||
}
|
||||
|
||||
@ -94,12 +94,11 @@ fn collect_displayed_rows(tree: &FsTree, selected_node_id: NodeId, terminal_rows
|
||||
(displayed_rows, cursor_y)
|
||||
}
|
||||
|
||||
fn move_cursor<'a, F>(tree: &'a FsTree, cursor: &mut Option<NodeId>, func: F) -> Option<NodeRef<'a, FsTreeViewNode>> where F: FnOnce(&FsTreeView, &NodeRef<FsTreeViewNode>) -> Option<NodeId> {
|
||||
let view = &tree.view;
|
||||
fn move_cursor<'a, F>(tree: &'a FsTree, cursor: &mut Option<NodeId>, func: F) -> Option<NodeRef<'a, FsTreeViewNode>> where F: FnOnce(NodeRef<FsTreeViewNode>) -> Option<NodeId> {
|
||||
let next_node = cursor
|
||||
.and_then(|id| view.get(id))
|
||||
.and_then(|node| func(view, &node))
|
||||
.and_then(|id| view.get(id));
|
||||
.and_then(|id| tree.get_view_node(id))
|
||||
.and_then(func)
|
||||
.and_then(|id| tree.get_view_node(id));
|
||||
|
||||
*cursor = next_node.as_ref().map(NodeRef::node_id);
|
||||
|
||||
|
@ -2,6 +2,7 @@ use std::path::Path;
|
||||
|
||||
use slab_tree::{NodeId, NodeRef};
|
||||
|
||||
use crate::component::filesystem::tree::view::FsTreeViewIterator;
|
||||
use crate::file::FileEntry;
|
||||
|
||||
pub use self::model::FsTreeModel;
|
||||
@ -14,7 +15,7 @@ mod view;
|
||||
|
||||
pub struct FsTree {
|
||||
model: FsTreeModel,
|
||||
pub view: FsTreeView,
|
||||
view: FsTreeView,
|
||||
pub selected_view_node_id: NodeId,
|
||||
structure_version: u32,
|
||||
}
|
||||
@ -44,6 +45,14 @@ impl FsTree {
|
||||
return self.view.get(self.selected_view_node_id);
|
||||
}
|
||||
|
||||
pub fn view_root_node(&self) -> Option<NodeRef<FsTreeViewNode>> {
|
||||
self.view.root()
|
||||
}
|
||||
|
||||
pub fn view_iter(&self) -> FsTreeViewIterator {
|
||||
self.view.into_iter()
|
||||
}
|
||||
|
||||
pub fn get_view_node(&self, view_node_id: NodeId) -> Option<NodeRef<FsTreeViewNode>> {
|
||||
self.view.get(view_node_id)
|
||||
}
|
||||
@ -105,7 +114,7 @@ impl FsTree {
|
||||
let view = &mut self.view;
|
||||
|
||||
if self.selected_view_node_id == view_node_id {
|
||||
self.selected_view_node_id = view.get_node_below_id(view_node_id).or_else(|| view.get_node_above_id(view_node_id)).unwrap_or_else(|| view.root_id());
|
||||
self.selected_view_node_id = view.get(view_node_id).and_then(|node| node.below_id().or_else(|| node.above_id())).unwrap_or_else(|| view.root_id());
|
||||
}
|
||||
|
||||
if let Some(view_node) = view.remove(view_node_id) {
|
||||
|
@ -5,7 +5,6 @@ use slab_tree::NodeId;
|
||||
|
||||
use crate::component::filesystem::tree::{FsTreeModel, FsTreeModelNode};
|
||||
use crate::file::FileEntry;
|
||||
use crate::util::slab_tree::{NodeMutExtensions, NodeRefExtensions};
|
||||
|
||||
impl FsTreeModel {
|
||||
pub fn resolve_children(&mut self, node_id: NodeId) -> Option<Vec<NodeId>> {
|
||||
|
@ -1,48 +0,0 @@
|
||||
use slab_tree::{NodeId, NodeRef};
|
||||
|
||||
use crate::component::filesystem::tree::{FsTreeView, FsTreeViewNode};
|
||||
use crate::util::slab_tree::NodeRefExtensions;
|
||||
|
||||
impl FsTreeView {
|
||||
pub fn get_node_above(&self, node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> {
|
||||
if let Some(prev_sibling_id) = node.prev_sibling_id() {
|
||||
Some(self.get_last_descendant_or_self(prev_sibling_id))
|
||||
} else {
|
||||
node.parent_id()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
pub fn get_node_below(&self, node: &NodeRef<FsTreeViewNode>) -> Option<NodeId> {
|
||||
if let Some(next_id) = node.first_child_id() {
|
||||
Some(next_id)
|
||||
} else if let Some(next_id) = node.next_sibling_id() {
|
||||
Some(next_id)
|
||||
} else {
|
||||
for ancestor in node.ancestors() {
|
||||
if let Some(next_id) = ancestor.next_sibling_id() {
|
||||
return Some(next_id);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_node_above_id(&self, node_id: NodeId) -> Option<NodeId> {
|
||||
self.get(node_id).and_then(|node| self.get_node_above(&node))
|
||||
}
|
||||
|
||||
pub fn get_node_below_id(&self, node_id: NodeId) -> Option<NodeId> {
|
||||
self.get(node_id).and_then(|node| self.get_node_below(&node))
|
||||
}
|
||||
|
||||
pub fn get_last_descendant_or_self(&self, id: NodeId) -> NodeId {
|
||||
let mut id = id;
|
||||
|
||||
while let Some(node_id) = self.get(id).and_then(|node| node.last_child_id()) {
|
||||
id = node_id;
|
||||
}
|
||||
|
||||
id
|
||||
}
|
||||
}
|
@ -2,7 +2,8 @@ use slab_tree::{NodeId, NodeMut, NodeRef, RemoveBehavior, Tree};
|
||||
|
||||
use crate::component::filesystem::tree::FsTreeModel;
|
||||
|
||||
mod above_below;
|
||||
pub use self::iterator::FsTreeViewIterator;
|
||||
|
||||
mod expand_collapse;
|
||||
mod iterator;
|
||||
mod refresh;
|
||||
|
@ -4,13 +4,13 @@ use crate::component::filesystem::tree::{FsTreeModel, FsTreeView, FsTreeViewNode
|
||||
|
||||
impl FsTreeView {
|
||||
pub fn traverse_up_root(&mut self, model: &mut FsTreeModel) -> Option<NodeId> {
|
||||
let old_moodel_root_id = model.root_id();
|
||||
let old_model_root_id = model.root_id();
|
||||
|
||||
if let Some(new_model_root_id) = model.traverse_up_root() {
|
||||
self.set_root(new_model_root_id);
|
||||
|
||||
if let Some(mut new_view_root) = self.get_mut(self.root_id) {
|
||||
Self::resolve_new_root_children(&mut new_view_root, model, old_moodel_root_id, new_model_root_id);
|
||||
Self::resolve_new_root_children(&mut new_view_root, model, old_model_root_id, new_model_root_id);
|
||||
Some(self.root_id)
|
||||
} else {
|
||||
None
|
||||
|
@ -1,4 +1,3 @@
|
||||
pub use integer_length::int_len;
|
||||
|
||||
mod integer_length;
|
||||
pub mod slab_tree;
|
||||
|
@ -1,61 +0,0 @@
|
||||
use slab_tree::{NodeId, NodeMut, NodeRef};
|
||||
|
||||
pub trait NodeRefExtensions {
|
||||
fn parent_id(&self) -> Option<NodeId>;
|
||||
fn first_child_id(&self) -> Option<NodeId>;
|
||||
fn last_child_id(&self) -> Option<NodeId>;
|
||||
fn prev_sibling_id(&self) -> Option<NodeId>;
|
||||
fn next_sibling_id(&self) -> Option<NodeId>;
|
||||
}
|
||||
|
||||
pub trait NodeMutExtensions {
|
||||
fn parent_id(&mut self) -> Option<NodeId>;
|
||||
fn first_child_id(&mut self) -> Option<NodeId>;
|
||||
fn last_child_id(&mut self) -> Option<NodeId>;
|
||||
fn prev_sibling_id(&mut self) -> Option<NodeId>;
|
||||
fn next_sibling_id(&mut self) -> Option<NodeId>;
|
||||
}
|
||||
|
||||
impl<'a, T> NodeRefExtensions for NodeRef<'a, T> {
|
||||
fn parent_id(&self) -> Option<NodeId> {
|
||||
self.parent().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
fn first_child_id(&self) -> Option<NodeId> {
|
||||
self.first_child().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
fn last_child_id(&self) -> Option<NodeId> {
|
||||
self.last_child().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
fn prev_sibling_id(&self) -> Option<NodeId> {
|
||||
self.prev_sibling().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
fn next_sibling_id(&self) -> Option<NodeId> {
|
||||
self.next_sibling().map(|node| node.node_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> NodeMutExtensions for NodeMut<'a, T> {
|
||||
fn parent_id(&mut self) -> Option<NodeId> {
|
||||
self.parent().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
fn first_child_id(&mut self) -> Option<NodeId> {
|
||||
self.first_child().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
fn last_child_id(&mut self) -> Option<NodeId> {
|
||||
self.last_child().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
fn prev_sibling_id(&mut self) -> Option<NodeId> {
|
||||
self.prev_sibling().map(|node| node.node_id())
|
||||
}
|
||||
|
||||
fn next_sibling_id(&mut self) -> Option<NodeId> {
|
||||
self.next_sibling().map(|node| node.node_id())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user