blob: 9fc5c6cb98d645fddd154da6b7541d8fff1c2339 [file] [log] [blame]
//! A library for creating and modifying Tree structures.
//!
//! ## Overview
//! In this implementation, the `Tree` owns all of the `Node`s and all inter-`Node` relationships
//! are managed with `NodeId`s.
//!
//! `Tree`s in this library are "just" trees. They do not allow cycles. They do not allow
//! the creation of arbitrary Graph structures. There is no weight associated with edges between
//! `Node`s. In addition, each `Node` can have an arbitrary number of child `Node`s.
//!
//! It is important to note that this library does not support comparison-based `Node` insertion.
//! In other words, this is not a Binary Search Tree (or any other kind of search tree) library.
//! It is purely a library for storing data in a hierarchical manner. The caller must know the
//! structure that they wish to build and then use this library to do so; this library will not
//! make those structural decisions for you.
//!
//! ## Example Usage
//! ```
//! use id_tree::*;
//!
//! fn main() {
//! use id_tree::InsertBehavior::*;
//!
//! // 0
//! // / \
//! // 1 2
//! // / \
//! // 3 4
//! let mut tree: Tree<i32> = TreeBuilder::new()
//! .with_node_capacity(5)
//! .build();
//!
//! let root_id: NodeId = tree.insert(Node::new(0), AsRoot).unwrap();
//! let child_id: NodeId = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
//! tree.insert(Node::new(2), UnderNode(&root_id)).unwrap();
//! tree.insert(Node::new(3), UnderNode(&child_id)).unwrap();
//! tree.insert(Node::new(4), UnderNode(&child_id)).unwrap();
//!
//! println!("Pre-order:");
//! for node in tree.traverse_pre_order(&root_id).unwrap() {
//! print!("{}, ", node.data());
//! }
//! // results in the output "0, 1, 3, 4, 2, "
//! }
//! ```
//!
//! ## Project Goals
//! * Allow caller control of as many allocations as possible (through pre-allocation)
//! * Fast `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
//!
//! #### Drawbacks of this Library
//! Sadly, Rust's ownership/reference system is sidestepped a bit by this implementation and this
//! can cause issues if the caller doesn't pay attention to what they are doing with `NodeId`s.
//!
//! We try to solve these issues with very careful usage of `NodeId`s so that the caller doesn't
//! have to be bothered (too much) with these concerns.
//!
//! Please see the [Potential `NodeId` Issues](struct.NodeId.html#potential-nodeid-issues) section
//! of the `NodeId` documentation for more info on what these issues are and how this library
//! attempts to solve them.
//!
#[cfg(feature = "serde_support")]
extern crate serde;
#[cfg(feature = "serde_support")]
#[macro_use]
extern crate serde_derive;
extern crate snowflake;
use self::snowflake::ProcessUniqueId;
mod behaviors;
mod error;
mod iterators;
mod node;
mod tree;
pub use behaviors::InsertBehavior;
pub use behaviors::MoveBehavior;
pub use behaviors::RemoveBehavior;
pub use behaviors::SwapBehavior;
pub use error::NodeIdError;
pub use iterators::AncestorIds;
pub use iterators::Ancestors;
pub use iterators::Children;
pub use iterators::ChildrenIds;
pub use iterators::LevelOrderTraversal;
pub use iterators::LevelOrderTraversalIds;
pub use iterators::PostOrderTraversal;
pub use iterators::PostOrderTraversalIds;
pub use iterators::PreOrderTraversal;
pub use iterators::PreOrderTraversalIds;
pub use node::Node;
pub use node::NodeBuilder;
pub use tree::Tree;
pub use tree::TreeBuilder;
///
/// An identifier used to differentiate between `Node`s within a `Tree`.
///
/// `NodeId`s are not something that the calling context will ever have to worry about generating.
/// `Tree`s generate `NodeId`s as `Node`s are inserted into them.
///
/// In addition, each `NodeId` is specific to the `Tree` that generated it. This means that if
/// there are two `Tree`s - `A` and `B` - there's no worry of trying to access a `Node` in `A` with
/// an identifier that came from `B`. Doing so will return a `Result::Err` value instead of
/// returning the wrong `Node`.
///
/// #### Potential `NodeId` Issues
///
/// Because `Tree`s pass out `NodeId`s as `Node`s are inserted, several issues can occur:
///
/// 1. If a `Node` is removed, the `NodeId` that previously identified it now points to nothing
/// (technically a `None` value in this case).
/// 2. If a `Node` is removed and then another is inserted later, the "new" `NodeId` that is
/// returned can (and will) be the same `NodeId` that was used to identify a different `Node`
/// previously.
///
/// The above issues may seem like deal-breakers, but our situation isn't as bad as it seems:
///
/// The first issue can be easily detected by the library itself. In this situation, a
/// `Result::Err` will be returned with the appropriate `NodeIdError`. The second issue, however, is
/// not something that the library can detect. To mitigate this problem, this library ensures the
/// following:
///
/// 1. All `Node` methods that provide `NodeId`s will **return** `&NodeId`s instead of `NodeId`s.
/// 2. All `Tree` methods that **read** or **insert** data accept `&NodeId`s instead of taking
/// `NodeId`s.
/// 3. All `Tree` methods that **remove** data take `NodeId`s instead of accepting `&NodeId`s.
/// 4. All `Node`s that have been removed from a `Tree` will have their parent and child references
/// cleared (to avoid leaking extra `NodeId` copies).
/// 5. `NodeId`s themselves are `Clone`, but not `Copy`.
///
/// This means that no methods will ever take ownership of a `NodeId` except for methods that remove
/// a `Node` from a `Tree`. The resulting behavior is that unless the caller **explicitly `Clone`s a
/// `NodeId`** they should never be in a situation where they accidentally hold onto a `NodeId` too
/// long. This means that we have "almost safe references" that the caller can clone if they choose
/// to. Doing so, however, will open up the possibility of confusing which `NodeId`s refer to which
/// `Node`s in the calling context.
///
/// This _does_ transfer some of the burden to the caller, but any errors should be fairly easy to
/// sort out because an explicit `Clone` is required for such an error to occur.
///
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[cfg_attr(feature = "serde_support", derive(Serialize))]
pub struct NodeId {
tree_id: ProcessUniqueId,
index: usize,
}