{"id":13439133,"url":"https://github.com/orium/rpds","last_synced_at":"2025-04-23T20:59:11.692Z","repository":{"id":26848871,"uuid":"96410740","full_name":"orium/rpds","owner":"orium","description":"Rust persistent data structures","archived":false,"fork":false,"pushed_at":"2025-04-08T18:54:56.000Z","size":690,"stargazers_count":1471,"open_issues_count":34,"forks_count":61,"subscribers_count":22,"default_branch":"main","last_synced_at":"2025-04-23T20:59:05.155Z","etag":null,"topics":["data-structure","data-structures","immutable-data-structures","persistent-data-structure","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/orium.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-06T09:06:16.000Z","updated_at":"2025-04-22T18:44:47.000Z","dependencies_parsed_at":"2023-11-28T23:28:21.502Z","dependency_job_id":"55a1c763-3a56-4bfd-9137-4dbc39b91ba0","html_url":"https://github.com/orium/rpds","commit_stats":{"total_commits":235,"total_committers":9,"mean_commits":26.11111111111111,"dds":"0.13617021276595742","last_synced_commit":"cdb547f10ca8d7b3ff4b1572684ec8a002984285"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orium%2Frpds","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orium%2Frpds/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orium%2Frpds/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orium%2Frpds/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/orium","download_url":"https://codeload.github.com/orium/rpds/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250514767,"owners_count":21443208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-structure","data-structures","immutable-data-structures","persistent-data-structure","rust"],"created_at":"2024-07-31T03:01:11.426Z","updated_at":"2025-04-23T20:59:11.666Z","avatar_url":"https://github.com/orium.png","language":"Rust","funding_links":[],"categories":["Libraries","Rust","库 Libraries","库"],"sub_categories":["Data structures","数据结构 Data structures","数据结构"],"readme":"[![Build Status](https://github.com/orium/rpds/workflows/CI/badge.svg)](https://github.com/orium/rpds/actions?query=workflow%3ACI)\n[![Code Coverage](https://codecov.io/gh/orium/rpds/branch/main/graph/badge.svg)](https://codecov.io/gh/orium/rpds)\n[![Dependency status](https://deps.rs/repo/github/orium/rpds/status.svg)](https://deps.rs/repo/github/orium/rpds)\n[![crates.io](https://img.shields.io/crates/v/rpds.svg)](https://crates.io/crates/rpds)\n[![Downloads](https://img.shields.io/crates/d/rpds.svg)](https://crates.io/crates/rpds)\n[![Github stars](https://img.shields.io/github/stars/orium/rpds.svg?logo=github)](https://github.com/orium/rpds/stargazers)\n[![Documentation](https://docs.rs/rpds/badge.svg)](https://docs.rs/rpds/)\n[![License](https://img.shields.io/crates/l/rpds.svg)](./LICENSE.md)\n\n# Rust Persistent Data Structures\n\n\u003c!-- cargo-rdme start --\u003e\n\nRust Persistent Data Structures provides [fully persistent data structures](https://en.wikipedia.org/wiki/Persistent_data_structure)\nwith structural sharing.\n\n## Setup\n\nTo use rpds add the following to your `Cargo.toml`:\n\n```toml\n[dependencies]\nrpds = \"\u003cversion\u003e\"\n```\n\n## Data structures\n\nThis crate offers the following data structures:\n\n  1. [`List`](#list)\n  2. [`Vector`](#vector)\n  3. [`Stack`](#stack)\n  4. [`Queue`](#queue)\n  5. [`HashTrieMap`](#hashtriemap)\n  6. [`HashTrieSet`](#hashtrieset)\n  7. [`RedBlackTreeMap`](#redblacktreemap)\n  8. [`RedBlackTreeSet`](#redblacktreeset)\n\n### `List`\n[![List documentation](https://img.shields.io/badge/doc-List-303070.svg)](https://docs.rs/rpds/latest/rpds/list/struct.List.html)\n\nYour classic functional list.\n\n#### Example\n\n```rust\nuse rpds::List;\n\nlet list = List::new().push_front(\"list\");\n\nassert_eq!(list.first(), Some(\u0026\"list\"));\n\nlet a_list = list.push_front(\"a\");\n\nassert_eq!(a_list.first(), Some(\u0026\"a\"));\n\nlet list_dropped = a_list.drop_first().unwrap();\n\nassert_eq!(list_dropped, list);\n```\n\n### `Vector`\n[![`Vector` documentation](https://img.shields.io/badge/doc-Vector-303070.svg)](https://docs.rs/rpds/latest/rpds/vector/struct.Vector.html)\n\nA sequence that can be indexed.  The implementation is described in\n[Understanding Persistent Vector Part 1](http://hypirion.com/musings/understanding-persistent-vector-pt-1)\nand [Understanding Persistent Vector Part 2](http://hypirion.com/musings/understanding-persistent-vector-pt-2).\n\n#### Example\n\n```rust\nuse rpds::Vector;\n\nlet vector = Vector::new()\n    .push_back(\"I’m\")\n    .push_back(\"a\")\n    .push_back(\"vector\");\n\nassert_eq!(vector[1], \"a\");\n\nlet screaming_vector = vector\n    .drop_last().unwrap()\n    .push_back(\"VECTOR!!!\");\n\nassert_eq!(screaming_vector[2], \"VECTOR!!!\");\n```\n\n### `Stack`\n[![`Stack` documentation](https://img.shields.io/badge/doc-Stack-303070.svg)](https://docs.rs/rpds/latest/rpds/stack/struct.Stack.html)\n\nA LIFO (last in, first out) data structure.  This is just a [`List`](#list) in disguise.\n\n#### Example\n\n```rust\nuse rpds::Stack;\n\nlet stack = Stack::new().push(\"stack\");\n\nassert_eq!(stack.peek(), Some(\u0026\"stack\"));\n\nlet a_stack = stack.push(\"a\");\n\nassert_eq!(a_stack.peek(), Some(\u0026\"a\"));\n\nlet stack_popped = a_stack.pop().unwrap();\n\nassert_eq!(stack_popped, stack);\n```\n\n### `Queue`\n[![`Queue` documentation](https://img.shields.io/badge/doc-Queue-303070.svg)](https://docs.rs/rpds/latest/rpds/queue/struct.Queue.html)\n\nA FIFO (first in, first out) data structure.\n\n#### Example\n\n```rust\nuse rpds::Queue;\n\nlet queue = Queue::new()\n    .enqueue(\"um\")\n    .enqueue(\"dois\")\n    .enqueue(\"tres\");\n\nassert_eq!(queue.peek(), Some(\u0026\"um\"));\n\nlet queue_dequeued = queue.dequeue().unwrap();\n\nassert_eq!(queue_dequeued.peek(), Some(\u0026\"dois\"));\n```\n\n### `HashTrieMap`\n[![`HashTrieMap` documentation](https://img.shields.io/badge/doc-HashTrieMap-303070.svg)](https://docs.rs/rpds/latest/rpds/map/hash_trie_map/struct.HashTrieMap.html)\n\nA map implemented with a [hash array mapped trie](https://en.wikipedia.org/wiki/Hash_array_mapped_trie).\nSee [Ideal Hash Trees](https://infoscience.epfl.ch/record/64398/files/idealhashtrees.pdf) for\ndetails.\n\n#### Example\n\n```rust\nuse rpds::HashTrieMap;\n\nlet map_en = HashTrieMap::new()\n    .insert(0, \"zero\")\n    .insert(1, \"one\");\n\nassert_eq!(map_en.get(\u00261), Some(\u0026\"one\"));\n\nlet map_pt = map_en\n    .insert(1, \"um\")\n    .insert(2, \"dois\");\n\nassert_eq!(map_pt.get(\u00262), Some(\u0026\"dois\"));\n\nlet map_pt_binary = map_pt.remove(\u00262);\n\nassert_eq!(map_pt_binary.get(\u00262), None);\n```\n\n### `HashTrieSet`\n[![`HashTrieSet` documentation](https://img.shields.io/badge/doc-HashTrieSet-303070.svg)](https://docs.rs/rpds/latest/rpds/set/hash_trie_set/struct.HashTrieSet.html)\n\nA set implemented with a [`HashTrieMap`](#hashtriemap).\n\n#### Example\n\n```rust\nuse rpds::HashTrieSet;\n\nlet set = HashTrieSet::new()\n    .insert(\"zero\")\n    .insert(\"one\");\n\nassert!(set.contains(\u0026\"one\"));\n\nlet set_extended = set.insert(\"two\");\n\nassert!(set_extended.contains(\u0026\"two\"));\n\nlet set_positive = set_extended.remove(\u0026\"zero\");\n\nassert!(!set_positive.contains(\u0026\"zero\"));\n```\n\n### `RedBlackTreeMap`\n[![`RedBlackTreeMap` documentation](https://img.shields.io/badge/doc-RedBlackTreeMap-303070.svg)](https://docs.rs/rpds/latest/rpds/map/red_black_tree_map/struct.RedBlackTreeMap.html)\n\nA map implemented with a [red-black tree](https://en.wikipedia.org/wiki/Red-Black_tree).\n\n#### Example\n\n```rust\nuse rpds::RedBlackTreeMap;\n\nlet map_en = RedBlackTreeMap::new()\n    .insert(0, \"zero\")\n    .insert(1, \"one\");\n\nassert_eq!(map_en.get(\u00261), Some(\u0026\"one\"));\n\nlet map_pt = map_en\n    .insert(1, \"um\")\n    .insert(2, \"dois\");\n\nassert_eq!(map_pt.get(\u00262), Some(\u0026\"dois\"));\n\nlet map_pt_binary = map_pt.remove(\u00262);\n\nassert_eq!(map_pt_binary.get(\u00262), None);\n\nassert_eq!(map_pt_binary.first(), Some((\u00260, \u0026\"zero\")));\n```\n\n### `RedBlackTreeSet`\n[![`RedBlackTreeSet` documentation](https://img.shields.io/badge/doc-RedBlackTreeSet-303070.svg)](https://docs.rs/rpds/latest/rpds/set/red_black_tree_set/struct.RedBlackTreeSet.html)\n\nA set implemented with a [`RedBlackTreeMap`](#redblacktreemap).\n\n#### Example\n\n```rust\nuse rpds::RedBlackTreeSet;\n\nlet set = RedBlackTreeSet::new()\n    .insert(\"zero\")\n    .insert(\"one\");\n\nassert!(set.contains(\u0026\"one\"));\n\nlet set_extended = set.insert(\"two\");\n\nassert!(set_extended.contains(\u0026\"two\"));\n\nlet set_positive = set_extended.remove(\u0026\"zero\");\n\nassert!(!set_positive.contains(\u0026\"zero\"));\n\nassert_eq!(set_positive.first(), Some(\u0026\"one\"));\n```\n\n## Other features\n\n### Mutable methods\n\nWhen you change a data structure you often do not need its previous versions.  For those cases\nrpds offers you mutable methods which are generally faster:\n\n```rust\nuse rpds::HashTrieSet;\n\nlet mut set = HashTrieSet::new();\n\nset.insert_mut(\"zero\");\nset.insert_mut(\"one\");\n\nlet set_0_1 = set.clone();\nlet set_0_1_2 = set.insert(\"two\");\n```\n\n### Initialization macros\n\nThere are convenient initialization macros for all data structures:\n\n```rust\nuse rpds::*;\n\nlet vector = vector![3, 1, 4, 1, 5];\nlet map = ht_map![\"orange\" =\u003e \"orange\", \"banana\" =\u003e \"yellow\"];\n```\n\nCheck the documentation for initialization macros of other data structures.\n\n### Thread safety\n\nAll data structures in this crate can be shared between threads, but that is an opt-in ability.\nThis is because there is a performance cost to make data structures thread safe.  That cost\nis worth avoiding when you are not actually sharing them between threads.\n\nOf course if you try to share a rpds data structure across different threads you can count on\nthe rust compiler to ensure that it is safe to do so.  If you are using the version of the data\nstructure that is not thread safe you will get a compile-time error.\n\nTo create a thread-safe version of any data structure use `new_sync()`:\n\n```rust\nlet vec = Vector::new_sync()\n    .push_back(42);\n```\n\nOr use the `_sync` variant of the initialization macro:\n\n```rust\nlet vec = vector_sync!(42);\n```\n\n#### Further details\n\nInternally the data structures in this crate maintain a lot of reference-counting pointers.\nThese pointers are used both for links between the internal nodes of the data structure as well\nas for the values it stores.\n\nThere are two implementations of reference-counting pointers in the standard library:\n[`Rc`](https://doc.rust-lang.org/stable/alloc/rc/struct.Rc.html) and\n[`Arc`](https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html).  They behave the same way, but\n`Arc` allows you to share the data it points to across multiple threads.  The downside is that\nit is significantly slower to clone and drop than `Rc`, and persistent data structures do a\nlot of those operations. In some microbenchmarks with rpds data structure we can see that\nusing `Rc` instead of  `Arc` can make some operations twice as fast!  You can see this for\nyourself by running `cargo bench`.\n\nTo implement this we parameterize the type of reference-counting pointer (`Rc` or `Arc`) as a\ntype argument of the data structure.  We use the [archery](https://github.com/orium/archery/)\ncrate to do this in a convenient way.\n\nThe pointer type can be parameterized like this:\n\n```rust\nlet vec: Vector\u003cu32, archery::ArcTK\u003e = Vector::new_with_ptr_kind();\n//                              ↖\n//                                This will use `Arc` pointers.\n//                                Change it to `archery::RcK` to use a `Rc` pointer.\n```\n\n### `no_std` support\n\nThis crate supports `no_std`.  To enable that you need to disable the default feature `std`:\n\n```toml\n[dependencies]\nrpds = { version = \"\u003cversion\u003e\", default-features = false }\n```\n\n### Serialization\n\nWe support serialization through [serde](https://crates.io/crates/serde).  To use it\nenable the `serde` feature.  To do so change the rpds dependency in your `Cargo.toml` to\n\n```toml\n[dependencies]\nrpds = { version = \"\u003cversion\u003e\", features = [\"serde\"] }\n```\n\n### Bindings\n\nBindings to use rpds from other programming languages exist. Below is a short list of those\nknown to date.\n\n* [rpds.py](https://github.com/crate-py/rpds/) – Python\n\nPlease feel free to send a pull request should you add support in a new language.\n\n\u003c!-- cargo-rdme end --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forium%2Frpds","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forium%2Frpds","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forium%2Frpds/lists"}