{"id":13648742,"url":"https://github.com/fitzgen/generational-arena","last_synced_at":"2025-04-22T11:33:04.665Z","repository":{"id":40553352,"uuid":"145510024","full_name":"fitzgen/generational-arena","owner":"fitzgen","description":"A safe arena allocator that allows deletion without suffering from the ABA problem by using generational indices.","archived":true,"fork":false,"pushed_at":"2023-08-18T21:09:58.000Z","size":77,"stargazers_count":678,"open_issues_count":17,"forks_count":52,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-09T10:49:06.542Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://docs.rs/generational-arena","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/fitzgen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-08-21T05:15:32.000Z","updated_at":"2025-04-03T07:09:13.000Z","dependencies_parsed_at":"2022-07-31T23:38:57.922Z","dependency_job_id":"479c7540-1e4e-4c01-acf6-9698c777683e","html_url":"https://github.com/fitzgen/generational-arena","commit_stats":{"total_commits":61,"total_committers":14,"mean_commits":4.357142857142857,"dds":"0.47540983606557374","last_synced_commit":"72975c8355949c2338976d944e047c9d9f447174"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fitzgen%2Fgenerational-arena","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fitzgen%2Fgenerational-arena/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fitzgen%2Fgenerational-arena/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fitzgen%2Fgenerational-arena/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fitzgen","download_url":"https://codeload.github.com/fitzgen/generational-arena/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250232482,"owners_count":21396648,"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":[],"created_at":"2024-08-02T01:04:30.028Z","updated_at":"2025-04-22T11:33:04.371Z","avatar_url":"https://github.com/fitzgen.png","language":"Rust","funding_links":[],"categories":["Rust","Memory Allocator"],"sub_categories":[],"readme":"# `generational-arena`\n\n[![](https://docs.rs/generational-arena/badge.svg)](https://docs.rs/generational-arena/)\n[![](https://img.shields.io/crates/v/generational-arena.svg)](https://crates.io/crates/generational-arena)\n[![](https://img.shields.io/crates/d/generational-arena.svg)](https://crates.io/crates/generational-arena)\n[![](https://github.com/fitzgen/generational-arena/actions/workflows/rust.yml/badge.svg)](https://github.com/fitzgen/generational-arena/actions/workflows/rust.yml)\n\nA safe arena allocator that allows deletion without suffering from [the ABA\nproblem](https://en.wikipedia.org/wiki/ABA_problem) by using generational\nindices.\n\nInspired by [Catherine West's closing keynote at RustConf\n2018](https://www.youtube.com/watch?v=aKLntZcp27M), where these ideas (and many\nmore!) were presented in the context of an Entity-Component-System for games\nprogramming.\n\n### What? Why?\n\nImagine you are working with a graph and you want to add and delete individual\nnodes at a time, or you are writing a game and its world consists of many\ninter-referencing objects with dynamic lifetimes that depend on user\ninput. These are situations where matching Rust's ownership and lifetime rules\ncan get tricky.\n\nIt doesn't make sense to use shared ownership with interior mutability (i.e.\n`Rc\u003cRefCell\u003cT\u003e\u003e` or `Arc\u003cMutex\u003cT\u003e\u003e`) nor borrowed references (ie `\u0026'a T` or `\u0026'a\nmut T`) for structures. The cycles rule out reference counted types, and the\nrequired shared mutability rules out borrows. Furthermore, lifetimes are dynamic\nand don't follow the borrowed-data-outlives-the-borrower discipline.\n\nIn these situations, it is tempting to store objects in a `Vec\u003cT\u003e` and have them\nreference each other via their indices. No more borrow checker or ownership\nproblems! Often, this solution is good enough.\n\nHowever, now we can't delete individual items from that `Vec\u003cT\u003e` when we no\nlonger need them, because we end up either\n\n* messing up the indices of every element that follows the deleted one, or\n\n* suffering from the [ABA\n  problem](https://en.wikipedia.org/wiki/ABA_problem). To elaborate further, if\n  we tried to replace the `Vec\u003cT\u003e` with a `Vec\u003cOption\u003cT\u003e\u003e`, and delete an\n  element by setting it to `None`, then we create the possibility for this buggy\n  sequence:\n\n    * `obj1` references `obj2` at index `i`\n\n    * someone else deletes `obj2` from index `i`, setting that element to `None`\n\n    * a third thing allocates `obj3`, which ends up at index `i`, because the\n      element at that index is `None` and therefore available for allocation\n\n    * `obj1` attempts to get `obj2` at index `i`, but incorrectly is given\n      `obj3`, when instead the get should fail.\n\nBy introducing a monotonically increasing generation counter to the collection,\nassociating each element in the collection with the generation when it was\ninserted, and getting elements from the collection with the *pair* of index and\nthe generation at the time when the element was inserted, then we can solve the\naforementioned ABA problem. When indexing into the collection, if the index\npair's generation does not match the generation of the element at that index,\nthen the operation fails.\n\n### Features\n\n* Zero `unsafe`\n* Well tested, including quickchecks\n* `no_std` compatibility\n* All the trait implementations you expect: `IntoIterator`, `FromIterator`,\n  `Extend`, etc...\n\n### Usage\n\nFirst, add `generational-arena` to your `Cargo.toml`:\n\n```toml\n[dependencies]\ngenerational-arena = \"0.2\"\n```\n\nThen, import the crate and use the\n[`generational_arena::Arena`](./struct.Arena.html) type!\n\n```rust\nextern crate generational_arena;\nuse generational_arena::Arena;\n\nlet mut arena = Arena::new();\n\n// Insert some elements into the arena.\nlet rza = arena.insert(\"Robert Fitzgerald Diggs\");\nlet gza = arena.insert(\"Gary Grice\");\nlet bill = arena.insert(\"Bill Gates\");\n\n// Inserted elements can be accessed infallibly via indexing (and missing\n// entries will panic).\nassert_eq!(arena[rza], \"Robert Fitzgerald Diggs\");\n\n// Alternatively, the `get` and `get_mut` methods provide fallible lookup.\nif let Some(genius) = arena.get(gza) {\n    println!(\"The gza gza genius: {}\", genius);\n}\nif let Some(val) = arena.get_mut(bill) {\n    *val = \"Bill Gates doesn't belong in this set...\";\n}\n\n// We can remove elements.\narena.remove(bill);\n\n// Insert a new one.\nlet murray = arena.insert(\"Bill Murray\");\n\n// The arena does not contain `bill` anymore, but it does contain `murray`, even\n// though they are almost certainly at the same index within the arena in\n// practice. Ambiguities are resolved with an associated generation tag.\nassert!(!arena.contains(bill));\nassert!(arena.contains(murray));\n\n// Iterate over everything inside the arena.\nfor (idx, value) in \u0026arena {\n    println!(\"{:?} is at {:?}\", value, idx);\n}\n```\n\n### `no_std`\n\nTo enable `no_std` compatibility, disable the on-by-default \"std\" feature.\n\n```toml\n[dependencies]\ngenerational-arena = { version = \"0.2\", default-features = false }\n```\n\n#### Serialization and Deserialization with [`serde`](https://crates.io/crates/serde)\n\nTo enable serialization/deserialization support, enable the \"serde\" feature.\n\n```toml\n[dependencies]\ngenerational-arena = { version = \"0.2\", features = [\"serde\"] }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffitzgen%2Fgenerational-arena","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffitzgen%2Fgenerational-arena","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffitzgen%2Fgenerational-arena/lists"}