tree_ds/lib.rs
1//! # Tree-DS
2//! A simple tree data structure implementation in Rust. It can be used in both `std` and `no_std`
3//! environments.
4//!
5//! The tree data structure is a hierarchical data structure that consists of nodes connected by
6//! edges. Each node in the tree can have zero or more children nodes. The tree data structure
7//! is used in various applications, such as file systems, computer science, and biology.
8//!
9//! A note on the choice of return types for the tree operations:
10//! - The tree operations return a `Result` type to handle errors that may occur during the operation.
11//! - For operations that return a value that may or may not be present, the return type is an `Option`.
12//!
13//! So for instance when you add a node to the tree, the return type is a `Result<NodeId>` because an
14//! error may occur during the operation. When you get a node from the tree, the return type is an
15//! `Option<&Node<T, Q>>` because the node may or may not be present in the tree.
16//!
17//! ## Usage
18//!
19//! ```rust
20//! use tree_ds::prelude::*;
21//!
22//!
23//! let mut tree: Tree<i32, i32> = Tree::new(Some("Sample Tree"));
24//! let root = tree.add_node(Node::new(1, Some(2)), None).unwrap();
25//! let child_1 = tree.add_node(Node::new(2, Some(3)), Some(&root)).unwrap();
26//! let child_2 = tree.add_node(Node::new(3, Some(4)), Some(&child_1)).unwrap();
27//! let child_3 = tree.add_node(Node::new(4, Some(5)), Some(&child_2)).unwrap();
28//! let sub_tree = tree.get_subtree(&child_2, None);
29//!
30//! ```
31//!
32//! ## Nodes
33//! A Node is the building blocks of the tree data structure. Each node in the tree can have a value
34//! and a unique ID. The value can be of any type that implements the `Eq`, `PartialEq` and `Clone`
35//! traits.
36//!
37//! By default, the tree requires you to provide unique IDs for the nodes. This node Ids can be of
38//! any type that implements the `Eq` and `Clone` traits.
39//!
40//! ```rust
41//! use tree_ds::prelude::*;
42//!
43//! let node = Node::new(1, Some(2));
44//! ```
45//! However, you can enable the `auto_id` feature to generate IDs automatically. This is useful when
46//! you want to create a node without specifying the ID. For a node to be created with an auto-generated
47//! ID, the `Q` type must implement the `From<u128>` trait.
48//!
49//! ```rust, ignore
50//! use tree_ds::prelude::*;
51//!
52//! let node = Node::<AutomatedId, &str>::new_with_auto_id(Some("Harry Doe"));
53//! let node_2 = Node::<AutomatedId, &str>::new_with_auto_id(Some("Jane Doe"));
54//! assert_ne!(node.get_node_id(), node_2.get_node_id());//!
55//! ```
56//!
57//! ## Traversal
58//! The tree supports three traversal strategies:
59//! - Pre-order
60//! - Post-order
61//! - In-order
62//!
63//! Consider the following tree:
64//! ```text
65//! Node 1: 2
66//! └── Node 2: 3
67//! └── Node 3: 4
68//! └── Node 4: 5
69//! ```
70//!
71//! You can modify nodes during traversal by using the iterator from the returned traversal data.
72//!
73//! ```rust
74//! use tree_ds::prelude::*;
75//!
76//!
77//! let mut tree = Tree::new(Some("Sample Tree"));
78//! let root = tree.add_node(Node::new("Node 1", Some(2)), None).unwrap();
79//! let child_1 = tree.add_node(Node::new("Node 2", Some(3)), Some(&root)).unwrap();
80//! let child_2 = tree.add_node(Node::new("Node 3", Some(4)), Some(&child_1)).unwrap();
81//! let child_3 = tree.add_node(Node::new("Node 4", Some(5)), Some(&child_2)).unwrap();
82//!
83//! tree.traverse(&root, TraversalStrategy::PreOrder).unwrap()
84//! .iter()
85//! .for_each(|node_id| {
86//! let node = tree.get_node_by_id(node_id).unwrap();
87//! let cur_value = node.get_value().unwrap().unwrap();
88//! node.set_value(Some(cur_value + 1)).unwrap();
89//! });
90//!
91//! # #[cfg(feature = "print_node_id")]
92//! # assert_eq!("Sample Tree\n***********\nNode 1: 3\n└── Node 2: 4\n └── Node 3: 5\n └── Node 4: 6\n", tree.to_string());
93//! # #[cfg(not(feature = "print_node_id"))]
94//! # assert_eq!("Sample Tree\n***********\n3\n└── 4\n └── 5\n └── 6\n", tree.to_string());
95//! # assert_eq!(tree.get_node_by_id(&root).unwrap().get_value().unwrap().unwrap(), 3);
96//!
97//!
98//! ```
99//!
100//! The newly modified tree will be:
101//! ```text
102//! Sample Tree
103//! ***********
104//! Node 1: 3
105//! └── Node 2: 4
106//! └── Node 3: 5
107//! └── Node 4: 6
108//! ```
109//!
110//! ## Serialization and Deserialization
111//! The tree data structure can be serialized and deserialized using the `serde` feature. By default,
112//! the tree serializes all the fields within the nodes. However, you can enable the `compact_serde`
113//! feature to serialize only the important node data that is sufficient to properly deserialize the
114//! node. This is useful when you want to serialize the tree and store it in a file or a database. The
115//! `compact_serde` feature is meant to be used with either the `serde` or the `no_std` feature. Enabling
116//! this feature without the `serde` or the `no_std` feature will result in nothing being serialized or
117//! deserialized. It should be noted that this feature adds an overhead when deserializing the data since
118//! the tree has to be reconstructed from the serialized data.
119//!
120//!
121//! ## `no_std` Environments.
122//! This crate can be used in `no_std` environments by enabling the `no_std` feature.
123//!
124//! ```toml
125//! [dependencies]
126//! tree-ds = { version = "0.1", features = ["no_std"] }
127//! ```
128//! The `no_std` feature disables the standard library and uses the `alloc` crate instead. The `alloc`
129//! crate provides the necessary types for the tree data structure to work in `no_std` environments.
130//! The `no_std` feature is useful when you want to use the tree data structure in embedded systems or
131//! environments where the standard library is not available. This feature also supports serialization
132//! and deserialization of the tree data structure as well as limited `auto_id` support.
133//!
134//!
135//! ## Cargo Features
136//! The following cargo features are also available:
137//! - By default the library is synchronous, and you need to manually provide ids for the nodes.
138//! - `async`: Enables support for async operations on the tree.
139//! - `serde`: Enables serialization and deserialization of the tree.
140//! - `auto_id`: Enables auto-generation of node IDs.
141//! - `no_std`: Disables the standard library.
142//! - `print_node_id`: Enables printing the node ID when printing the tree. It is disabled by default.
143//! - `compact-serde`: Enables compact serialization and deserialization of the tree. It is meant to be used with either the `serde` or the `no_std` features. Enabling this feature without the `serde` or the `no_std` feature will result in nothing being serialized or deserialized.
144
145#![cfg_attr(feature = "no_std", no_std)]
146
147#[cfg(feature = "no_std")]
148extern crate alloc;
149extern crate core;
150
151mod lib {
152 #[cfg(all(feature = "no_std", not(feature = "async")))]
153 pub use alloc::rc::Rc;
154 #[cfg(all(feature = "no_std", feature = "async"))]
155 pub use alloc::sync::Arc;
156 #[cfg(feature = "no_std")]
157 pub use alloc::{
158 collections::BTreeSet,
159 format,
160 string::{String, ToString},
161 vec,
162 vec::Vec,
163 };
164 #[cfg(feature = "async")]
165 pub use spin::RwLock;
166
167 #[cfg(all(test, not(feature = "no_std")))]
168 pub use std::format;
169 #[cfg(all(not(feature = "no_std"), not(feature = "async")))]
170 pub use std::rc::Rc;
171 #[cfg(all(not(feature = "no_std"), feature = "async"))]
172 pub use std::sync::Arc;
173 #[cfg(not(feature = "no_std"))]
174 pub use std::{
175 collections::HashSet,
176 string::{String, ToString},
177 vec,
178 vec::Vec,
179 };
180
181 #[cfg(not(feature = "async"))]
182 pub use self::core::cell::RefCell;
183 pub use self::core::clone::Clone;
184 pub use self::core::cmp::{Eq, Ordering, PartialEq};
185 pub use self::core::convert::{AsRef, From};
186 pub use self::core::default::Default;
187 pub use self::core::fmt::{Debug, Display, Error as FmtError, Formatter, Result as FmtResult};
188 pub use self::core::hash::{Hash, Hasher};
189 pub use self::core::option::Option;
190 pub use self::core::result::Result;
191 pub use self::core::slice::Iter;
192
193 mod core {
194 #[cfg(feature = "no_std")]
195 pub use core::*;
196
197 #[cfg(not(feature = "no_std"))]
198 pub use std::*;
199 }
200}
201
202mod error;
203mod node;
204mod tree;
205
206pub mod prelude {
207 //! A module to re-export the necessary types for the tree data structure.
208
209 pub use crate::{
210 node::{Node, Nodes},
211 tree::{NodeRemovalStrategy, SubTree, TraversalStrategy, Tree},
212 };
213
214 /// Defines the default type for the node id.
215 ///
216 /// The default type for the node id is `u128`.
217 #[cfg(feature = "auto_id")]
218 pub type AutomatedId = u128;
219
220 /// The error type for this crate.
221 pub type Result<T> = crate::lib::Result<T, crate::error::Error>;
222}