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//! # fn main() -> Result<()> {
77//! let mut tree = Tree::new(Some("Sample Tree"));
78//! let root = tree.add_node(Node::new("Node 1", Some(2)), None)?;
79//! let child_1 = tree.add_node(Node::new("Node 2", Some(3)), Some(&root))?;
80//! let child_2 = tree.add_node(Node::new("Node 3", Some(4)), Some(&child_1))?;
81//! let child_3 = tree.add_node(Node::new("Node 4", Some(5)), Some(&child_2))?;
82//!
83//! tree.traverse(&root, TraversalStrategy::PreOrder)?
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();
88//! node.set_value(Some(cur_value + 1));
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(), 3);
96//! # Ok(())
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;
149
150mod lib {
151 #[cfg(all(feature = "no_std", not(feature = "async")))]
152 pub use alloc::rc::Rc;
153 #[cfg(all(feature = "no_std", feature = "async"))]
154 pub use alloc::sync::Arc;
155 #[cfg(feature = "no_std")]
156 pub use alloc::{
157 collections::BTreeSet,
158 format,
159 string::{String, ToString},
160 vec,
161 vec::Vec,
162 };
163
164 #[cfg(all(test, not(feature = "no_std")))]
165 pub use std::format;
166 #[cfg(all(not(feature = "no_std"), not(feature = "async")))]
167 pub use std::rc::Rc;
168 #[cfg(all(not(feature = "no_std"), feature = "async"))]
169 pub use std::sync::Arc;
170 #[cfg(not(feature = "no_std"))]
171 pub use std::{
172 collections::HashSet,
173 string::{String, ToString},
174 vec,
175 vec::Vec,
176 };
177
178 pub use self::core::cell::RefCell;
179 pub use self::core::clone::Clone;
180 pub use self::core::cmp::{Eq, PartialEq};
181 pub use self::core::convert::{AsRef, From};
182 pub use self::core::default::Default;
183 pub use self::core::fmt::{Debug, Display, Error as FmtError, Formatter, Result as FmtResult};
184 pub use self::core::hash::{Hash, Hasher};
185 pub use self::core::option::Option;
186 pub use self::core::result::Result;
187 pub use self::core::slice::Iter;
188
189 mod core {
190 #[cfg(feature = "no_std")]
191 pub use core::*;
192
193 #[cfg(not(feature = "no_std"))]
194 pub use std::*;
195 }
196}
197
198mod error;
199mod node;
200mod tree;
201
202pub mod prelude {
203 //! A module to re-export the necessary types for the tree data structure.
204
205 pub use crate::{
206 node::{Node, Nodes},
207 tree::{NodeRemovalStrategy, SubTree, TraversalStrategy, Tree},
208 };
209
210 /// Defines the default type for the node id.
211 ///
212 /// The default type for the node id is `u128`.
213 #[cfg(feature = "auto_id")]
214 pub type AutomatedId = u128;
215
216 /// The error type for this crate.
217 pub type Result<T> = crate::lib::Result<T, crate::error::Error>;
218}