[go: up one dir, main page]

rpds/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2// Note: If you change this remember to update `README.md`. To do so run `cargo rdme`.
3//! Rust Persistent Data Structures provides [fully persistent data structures](https://en.wikipedia.org/wiki/Persistent_data_structure)
4//! with structural sharing.
5//!
6//! # Setup
7//!
8//! To use rpds add the following to your `Cargo.toml`:
9//!
10//! ```toml
11//! [dependencies]
12//! rpds = "<version>"
13//! ```
14//!
15//! # Data structures
16//!
17//! This crate offers the following data structures:
18//!
19//!   1. [`List`](#list)
20//!   2. [`Vector`](#vector)
21//!   3. [`Stack`](#stack)
22//!   4. [`Queue`](#queue)
23//!   5. [`HashTrieMap`](#hashtriemap)
24//!   6. [`HashTrieSet`](#hashtrieset)
25//!   7. [`RedBlackTreeMap`](#redblacktreemap)
26//!   8. [`RedBlackTreeSet`](#redblacktreeset)
27//!
28//! ## `List`
29//! [![List documentation](https://img.shields.io/badge/doc-List-303070.svg)](crate::list::List)
30//!
31//! Your classic functional list.
32//!
33//! ### Example
34//!
35//! ```rust
36//! use rpds::List;
37//!
38//! let list = List::new().push_front("list");
39//!
40//! assert_eq!(list.first(), Some(&"list"));
41//!
42//! let a_list = list.push_front("a");
43//!
44//! assert_eq!(a_list.first(), Some(&"a"));
45//!
46//! let list_dropped = a_list.drop_first().unwrap();
47//!
48//! assert_eq!(list_dropped, list);
49//! ```
50//!
51//! ## `Vector`
52//! [![`Vector` documentation](https://img.shields.io/badge/doc-Vector-303070.svg)](crate::vector::Vector)
53//!
54//! A sequence that can be indexed. The implementation is described in
55//! [Understanding Persistent Vector Part 1](http://hypirion.com/musings/understanding-persistent-vector-pt-1)
56//! and [Understanding Persistent Vector Part 2](http://hypirion.com/musings/understanding-persistent-vector-pt-2).
57//!
58//! ### Example
59//!
60//! ```rust
61//! use rpds::Vector;
62//!
63//! let vector = Vector::new()
64//!     .push_back("I’m")
65//!     .push_back("a")
66//!     .push_back("vector");
67//!
68//! assert_eq!(vector[1], "a");
69//!
70//! let screaming_vector = vector
71//!     .drop_last().unwrap()
72//!     .push_back("VECTOR!!!");
73//!
74//! assert_eq!(screaming_vector[2], "VECTOR!!!");
75//! ```
76//!
77//! ## `Stack`
78//! [![`Stack` documentation](https://img.shields.io/badge/doc-Stack-303070.svg)](crate::stack::Stack)
79//!
80//! A LIFO (last in, first out) data structure. This is just a [`List`](#list) in disguise.
81//!
82//! ### Example
83//!
84//! ```rust
85//! use rpds::Stack;
86//!
87//! let stack = Stack::new().push("stack");
88//!
89//! assert_eq!(stack.peek(), Some(&"stack"));
90//!
91//! let a_stack = stack.push("a");
92//!
93//! assert_eq!(a_stack.peek(), Some(&"a"));
94//!
95//! let stack_popped = a_stack.pop().unwrap();
96//!
97//! assert_eq!(stack_popped, stack);
98//! ```
99//!
100//! ## `Queue`
101//! [![`Queue` documentation](https://img.shields.io/badge/doc-Queue-303070.svg)](crate::queue::Queue)
102//!
103//! A FIFO (first in, first out) data structure.
104//!
105//! ### Example
106//!
107//! ```rust
108//! use rpds::Queue;
109//!
110//! let queue = Queue::new()
111//!     .enqueue("um")
112//!     .enqueue("dois")
113//!     .enqueue("tres");
114//!
115//! assert_eq!(queue.peek(), Some(&"um"));
116//!
117//! let queue_dequeued = queue.dequeue().unwrap();
118//!
119//! assert_eq!(queue_dequeued.peek(), Some(&"dois"));
120//! ```
121//!
122//! ## `HashTrieMap`
123//! [![`HashTrieMap` documentation](https://img.shields.io/badge/doc-HashTrieMap-303070.svg)](crate::map::hash_trie_map::HashTrieMap)
124//!
125//! A map implemented with a [hash array mapped trie](https://en.wikipedia.org/wiki/Hash_array_mapped_trie).
126//! See [Ideal Hash Trees](https://infoscience.epfl.ch/record/64398/files/idealhashtrees.pdf) for
127//! details.
128//!
129//! ### Example
130//!
131//! ```rust
132//! use rpds::HashTrieMap;
133//!
134//! let map_en = HashTrieMap::new()
135//!     .insert(0, "zero")
136//!     .insert(1, "one");
137//!
138//! assert_eq!(map_en.get(&1), Some(&"one"));
139//!
140//! let map_pt = map_en
141//!     .insert(1, "um")
142//!     .insert(2, "dois");
143//!
144//! assert_eq!(map_pt.get(&2), Some(&"dois"));
145//!
146//! let map_pt_binary = map_pt.remove(&2);
147//!
148//! assert_eq!(map_pt_binary.get(&2), None);
149//! ```
150//!
151//! ## `HashTrieSet`
152//! [![`HashTrieSet` documentation](https://img.shields.io/badge/doc-HashTrieSet-303070.svg)](crate::set::hash_trie_set::HashTrieSet)
153//!
154//! A set implemented with a [`HashTrieMap`](#hashtriemap).
155//!
156//! ### Example
157//!
158//! ```rust
159//! use rpds::HashTrieSet;
160//!
161//! let set = HashTrieSet::new()
162//!     .insert("zero")
163//!     .insert("one");
164//!
165//! assert!(set.contains(&"one"));
166//!
167//! let set_extended = set.insert("two");
168//!
169//! assert!(set_extended.contains(&"two"));
170//!
171//! let set_positive = set_extended.remove(&"zero");
172//!
173//! assert!(!set_positive.contains(&"zero"));
174//! ```
175//!
176//! ## `RedBlackTreeMap`
177//! [![`RedBlackTreeMap` documentation](https://img.shields.io/badge/doc-RedBlackTreeMap-303070.svg)](crate::map::red_black_tree_map::RedBlackTreeMap)
178//!
179//! A map implemented with a [red-black tree](https://en.wikipedia.org/wiki/Red-Black_tree).
180//!
181//! ### Example
182//!
183//! ```rust
184//! use rpds::RedBlackTreeMap;
185//!
186//! let map_en = RedBlackTreeMap::new()
187//!     .insert(0, "zero")
188//!     .insert(1, "one");
189//!
190//! assert_eq!(map_en.get(&1), Some(&"one"));
191//!
192//! let map_pt = map_en
193//!     .insert(1, "um")
194//!     .insert(2, "dois");
195//!
196//! assert_eq!(map_pt.get(&2), Some(&"dois"));
197//!
198//! let map_pt_binary = map_pt.remove(&2);
199//!
200//! assert_eq!(map_pt_binary.get(&2), None);
201//!
202//! assert_eq!(map_pt_binary.first(), Some((&0, &"zero")));
203//! ```
204//!
205//! ## `RedBlackTreeSet`
206//! [![`RedBlackTreeSet` documentation](https://img.shields.io/badge/doc-RedBlackTreeSet-303070.svg)](crate::set::red_black_tree_set::RedBlackTreeSet)
207//!
208//! A set implemented with a [`RedBlackTreeMap`](#redblacktreemap).
209//!
210//! ### Example
211//!
212//! ```rust
213//! use rpds::RedBlackTreeSet;
214//!
215//! let set = RedBlackTreeSet::new()
216//!     .insert("zero")
217//!     .insert("one");
218//!
219//! assert!(set.contains(&"one"));
220//!
221//! let set_extended = set.insert("two");
222//!
223//! assert!(set_extended.contains(&"two"));
224//!
225//! let set_positive = set_extended.remove(&"zero");
226//!
227//! assert!(!set_positive.contains(&"zero"));
228//!
229//! assert_eq!(set_positive.first(), Some(&"one"));
230//! ```
231//!
232//! # Other features
233//!
234//! ## Mutable methods
235//!
236//! When you change a data structure you often do not need its previous versions. For those cases
237//! rpds offers you mutable methods which are generally faster:
238//!
239//! ```rust
240//! use rpds::HashTrieSet;
241//!
242//! let mut set = HashTrieSet::new();
243//!
244//! set.insert_mut("zero");
245//! set.insert_mut("one");
246//!
247//! let set_0_1 = set.clone();
248//! let set_0_1_2 = set.insert("two");
249//! ```
250//!
251//! ## Initialization macros
252//!
253//! There are convenient initialization macros for all data structures:
254//!
255//! ```rust
256//! use rpds::*;
257//!
258//! let vector = vector![3, 1, 4, 1, 5];
259//! let map = ht_map!["orange" => "orange", "banana" => "yellow"];
260//! ```
261//!
262//! Check the documentation for initialization macros of other data structures.
263//!
264//! ## Thread safety
265//!
266//! All data structures in this crate can be shared between threads, but that is an opt-in ability.
267//! This is because there is a performance cost to make data structures thread safe. That cost
268//! is worth avoiding when you are not actually sharing them between threads.
269//!
270//! Of course if you try to share a rpds data structure across different threads you can count on
271//! the rust compiler to ensure that it is safe to do so. If you are using the version of the data
272//! structure that is not thread safe you will get a compile-time error.
273//!
274//! To create a thread-safe version of any data structure use `new_sync()`:
275//!
276//! ```rust
277//! # use rpds::Vector;
278//! #
279//! let vec = Vector::new_sync()
280//!     .push_back(42);
281//! ```
282//!
283//! Or use the `_sync` variant of the initialization macro:
284//!
285//! ```rust
286//! # use rpds::vector_sync;
287//! #
288//! let vec = vector_sync!(42);
289//! ```
290//!
291//! ### Further details
292//!
293//! Internally the data structures in this crate maintain a lot of reference-counting pointers.
294//! These pointers are used both for links between the internal nodes of the data structure as well
295//! as for the values it stores.
296//!
297//! There are two implementations of reference-counting pointers in the standard library:
298//! [`Rc`](::alloc::rc::Rc) and
299//! [`Arc`](::alloc::sync::Arc). They behave the same way, but
300//! `Arc` allows you to share the data it points to across multiple threads. The downside is that
301//! it is significantly slower to clone and drop than `Rc`, and persistent data structures do a
302//! lot of those operations. In some microbenchmarks with rpds data structure we can see that
303//! using `Rc` instead of  `Arc` can make some operations twice as fast!  You can see this for
304//! yourself by running `cargo bench`.
305//!
306//! To implement this we parameterize the type of reference-counting pointer (`Rc` or `Arc`) as a
307//! type argument of the data structure. We use the [archery](https://github.com/orium/archery/)
308//! crate to do this in a convenient way.
309//!
310//! The pointer type can be parameterized like this:
311//!
312//! ```rust
313//! # use rpds::Vector;
314//! #
315//! let vec: Vector<u32, archery::ArcTK> = Vector::new_with_ptr_kind();
316//! //                              ↖
317//! //                                This will use `Arc` pointers.
318//! //                                Change it to `archery::RcK` to use a `Rc` pointer.
319//! ```
320//!
321//! ## `no_std` support
322//!
323//! This crate supports `no_std`. To enable that you need to disable the default feature `std`:
324//!
325//! ```toml
326//! [dependencies]
327//! rpds = { version = "<version>", default-features = false }
328//! ```
329//!
330//! ## Parallel iterator support
331//!
332//! [`HashTrieMap`](crate::map::hash_trie_map::HashTrieMap) supports parallel iterator with
333//! [rayon](https://crates.io/crates/rayon). To use them you need to enable the `rayon` feature.
334//!
335//! ## Serialization
336//!
337//! We support serialization through [serde](https://crates.io/crates/serde). To use it
338//! enable the `serde` feature. To do so change the rpds dependency in your `Cargo.toml` to
339//!
340//! ```toml
341//! [dependencies]
342//! rpds = { version = "<version>", features = ["serde"] }
343//! ```
344//!
345//! ## Bindings
346//!
347//! Bindings to use rpds from other programming languages exist. Below is a short list of those
348//! known to date.
349//!
350//! * [rpds.py](https://github.com/crate-py/rpds/) – Python
351//!
352//! Please feel free to send a pull request should you add support in a new language.
353
354extern crate alloc;
355
356#[cfg(test)]
357#[macro_use]
358extern crate std;
359
360mod utils;
361#[macro_use]
362pub mod list;
363pub mod map;
364pub mod queue;
365pub mod set;
366pub mod stack;
367pub mod vector;
368
369pub use crate::list::List;
370pub use crate::list::ListSync;
371pub use crate::map::hash_trie_map::HashTrieMap;
372pub use crate::map::hash_trie_map::HashTrieMapSync;
373pub use crate::map::red_black_tree_map::RedBlackTreeMap;
374pub use crate::map::red_black_tree_map::RedBlackTreeMapSync;
375pub use crate::queue::Queue;
376pub use crate::queue::QueueSync;
377pub use crate::set::hash_trie_set::HashTrieSet;
378pub use crate::set::hash_trie_set::HashTrieSetSync;
379pub use crate::set::red_black_tree_set::RedBlackTreeSet;
380pub use crate::set::red_black_tree_set::RedBlackTreeSetSync;
381pub use crate::stack::Stack;
382pub use crate::stack::StackSync;
383pub use crate::vector::Vector;
384pub use crate::vector::VectorSync;