2019-09-06 15:57:44 -07:00

136 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `generational_arena` crate."><meta name="keywords" content="rust, rustlang, rust-lang, generational_arena"><title>generational_arena - Rust</title><link rel="stylesheet" type="text/css" href="../normalize.css"><link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle"><link rel="stylesheet" type="text/css" href="../dark.css"><link rel="stylesheet" type="text/css" href="../light.css" id="themeStyle"><script src="../storage.js"></script><noscript><link rel="stylesheet" href="../noscript.css"></noscript><link rel="shortcut icon" href="../favicon.ico"><style type="text/css">#crate-search{background-image:url("../down-arrow.svg");}</style></head><body class="rustdoc mod"><!--[if lte IE 8]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="sidebar-menu">&#9776;</div><a href='../generational_arena/index.html'><div class='logo-container'><img src='../rust-logo.png' alt='logo'></div></a><p class='location'>Crate generational_arena</p><div class="sidebar-elems"><a id='all-types' href='all.html'><p>See all generational_arena's items</p></a><div class="block items"><ul><li><a href="#structs">Structs</a></li></ul></div><p class='location'></p><script>window.sidebarCurrent = {name: 'generational_arena', ty: 'mod', relpath: '../'};</script></div></nav><div class="theme-picker"><button id="theme-picker" aria-label="Pick another theme!"><img src="../brush.svg" width="18" alt="Pick another theme!"></button><div id="theme-choices"></div></div><script src="../theme.js"></script><nav class="sub"><form class="search-form js-only"><div class="search-container"><div><select id="crate-search"><option value="All crates">All crates</option></select><input class="search-input" name="search" autocomplete="off" spellcheck="false" placeholder="Click or press S to search, ? for more options…" type="search"></div><a id="settings-menu" href="../settings.html"><img src="../wheel.svg" width="18" alt="Change settings"></a></div></form></nav><section id="main" class="content"><h1 class='fqn'><span class='out-of-band'><span id='render-detail'><a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">[<span class='inner'>&#x2212;</span>]</a></span><a class='srclink' href='../src/generational_arena/lib.rs.html#1-1161' title='goto source code'>[src]</a></span><span class='in-band'>Crate <a class="mod" href=''>generational_arena</a></span></h1><div class='docblock'><p><a href="https://docs.rs/generational-arena/"><img src="https://docs.rs/generational-arena/badge.svg" alt="" /></a>
<a href="https://crates.io/crates/generational-arena"><img src="https://img.shields.io/crates/v/generational-arena.svg" alt="" /></a>
<a href="https://crates.io/crates/generational-arena"><img src="https://img.shields.io/crates/d/generational-arena.svg" alt="" /></a>
<a href="https://travis-ci.org/fitzgen/generational-arena"><img src="https://travis-ci.org/fitzgen/generational-arena.svg?branch=master" alt="Travis CI Build Status" /></a></p>
<p>A safe arena allocator that allows deletion without suffering from <a href="https://en.wikipedia.org/wiki/ABA_problem">the ABA
problem</a> by using generational
indices.</p>
<p>Inspired by <a href="http://rustconf.com/program.html#closingkeynote">Catherine West's closing keynote at RustConf
2018</a>, where these ideas
were presented in the context of an Entity-Component-System for games
programming.</p>
<h2 id="what-why" class="section-header"><a href="#what-why">What? Why?</a></h2>
<p>Imagine you are working with a graph and you want to add and delete individual
nodes at a time, or you are writing a game and its world consists of many
inter-referencing objects with dynamic lifetimes that depend on user
input. These are situations where matching Rust's ownership and lifetime rules
can get tricky.</p>
<p>It doesn't make sense to use shared ownership with interior mutability (ie
<code>Rc&lt;RefCell&lt;T&gt;&gt;</code> or <code>Arc&lt;Mutex&lt;T&gt;&gt;</code>) nor borrowed references (ie <code>&amp;'a T</code> or <code>&amp;'a mut T</code>) for structures. The cycles rule out reference counted types, and the
required shared mutability rules out borrows. Furthermore, lifetimes are dynamic
and don't follow the borrowed-data-outlives-the-borrower discipline.</p>
<p>In these situations, it is tempting to store objects in a <code>Vec&lt;T&gt;</code> and have them
reference each other via their indices. No more borrow checker or ownership
problems! Often, this solution is good enough.</p>
<p>However, now we can't delete individual items from that <code>Vec&lt;T&gt;</code> when we no
longer need them, because we end up either</p>
<ul>
<li>
<p>messing up the indices of every element that follows the deleted one, or</p>
</li>
<li>
<p>suffering from the <a href="https://en.wikipedia.org/wiki/ABA_problem">ABA
problem</a>. To elaborate further, if
we tried to replace the <code>Vec&lt;T&gt;</code> with a <code>Vec&lt;Option&lt;T&gt;&gt;</code>, and delete an
element by setting it to <code>None</code>, then we create the possibility for this buggy
sequence:</p>
<ul>
<li>
<p><code>obj1</code> references <code>obj2</code> at index <code>i</code></p>
</li>
<li>
<p>someone else deletes <code>obj2</code> from index <code>i</code>, setting that element to <code>None</code></p>
</li>
<li>
<p>a third thing allocates <code>obj3</code>, which ends up at index <code>i</code>, because the
element at that index is <code>None</code> and therefore available for allocation</p>
</li>
<li>
<p><code>obj1</code> attempts to get <code>obj2</code> at index <code>i</code>, but incorrectly is given
<code>obj3</code>, when instead the get should fail.</p>
</li>
</ul>
</li>
</ul>
<p>By introducing a monotonically increasing generation counter to the collection,
associating each element in the collection with the generation when it was
inserted, and getting elements from the collection with the <em>pair</em> of index and
the generation at the time when the element was inserted, then we can solve the
aforementioned ABA problem. When indexing into the collection, if the index
pair's generation does not match the generation of the element at that index,
then the operation fails.</p>
<h2 id="features" class="section-header"><a href="#features">Features</a></h2>
<ul>
<li>Zero <code>unsafe</code></li>
<li>Well tested, including quickchecks</li>
<li><code>no_std</code> compatibility</li>
<li>All the trait implementations you expect: <code>IntoIterator</code>, <code>FromIterator</code>,
<code>Extend</code>, etc...</li>
</ul>
<h2 id="usage" class="section-header"><a href="#usage">Usage</a></h2>
<p>First, add <code>generational-arena</code> to your <code>Cargo.toml</code>:</p>
<pre><code class="language-toml">[dependencies]
generational-arena = &quot;0.1&quot;
</code></pre>
<p>Then, import the crate and use the
<a href="./struct.Arena.html"><code>generational_arena::Arena</code></a> type!</p>
<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="kw">extern</span> <span class="kw">crate</span> <span class="ident">generational_arena</span>;
<span class="kw">use</span> <span class="ident">generational_arena</span>::<span class="ident">Arena</span>;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">arena</span> <span class="op">=</span> <span class="ident">Arena</span>::<span class="ident">new</span>();
<span class="comment">// Insert some elements into the arena.</span>
<span class="kw">let</span> <span class="ident">rza</span> <span class="op">=</span> <span class="ident">arena</span>.<span class="ident">insert</span>(<span class="string">&quot;Robert Fitzgerald Diggs&quot;</span>);
<span class="kw">let</span> <span class="ident">gza</span> <span class="op">=</span> <span class="ident">arena</span>.<span class="ident">insert</span>(<span class="string">&quot;Gary Grice&quot;</span>);
<span class="kw">let</span> <span class="ident">bill</span> <span class="op">=</span> <span class="ident">arena</span>.<span class="ident">insert</span>(<span class="string">&quot;Bill Gates&quot;</span>);
<span class="comment">// Inserted elements can be accessed infallibly via indexing (and missing</span>
<span class="comment">// entries will panic).</span>
<span class="macro">assert_eq</span><span class="macro">!</span>(<span class="ident">arena</span>[<span class="ident">rza</span>], <span class="string">&quot;Robert Fitzgerald Diggs&quot;</span>);
<span class="comment">// Alternatively, the `get` and `get_mut` methods provide fallible lookup.</span>
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">genius</span>) <span class="op">=</span> <span class="ident">arena</span>.<span class="ident">get</span>(<span class="ident">gza</span>) {
<span class="macro">println</span><span class="macro">!</span>(<span class="string">&quot;The gza gza genius: {}&quot;</span>, <span class="ident">genius</span>);
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">val</span>) <span class="op">=</span> <span class="ident">arena</span>.<span class="ident">get_mut</span>(<span class="ident">bill</span>) {
<span class="kw-2">*</span><span class="ident">val</span> <span class="op">=</span> <span class="string">&quot;Bill Gates doesn&#39;t belong in this set...&quot;</span>;
}
<span class="comment">// We can remove elements.</span>
<span class="ident">arena</span>.<span class="ident">remove</span>(<span class="ident">bill</span>);
<span class="comment">// Insert a new one.</span>
<span class="kw">let</span> <span class="ident">murray</span> <span class="op">=</span> <span class="ident">arena</span>.<span class="ident">insert</span>(<span class="string">&quot;Bill Murray&quot;</span>);
<span class="comment">// The arena does not contain `bill` anymore, but it does contain `murray`, even</span>
<span class="comment">// though they are almost certainly at the same index within the arena in</span>
<span class="comment">// practice. Ambiguities are resolved with an associated generation tag.</span>
<span class="macro">assert</span><span class="macro">!</span>(<span class="op">!</span><span class="ident">arena</span>.<span class="ident">contains</span>(<span class="ident">bill</span>));
<span class="macro">assert</span><span class="macro">!</span>(<span class="ident">arena</span>.<span class="ident">contains</span>(<span class="ident">murray</span>));
<span class="comment">// Iterate over everything inside the arena.</span>
<span class="kw">for</span> (<span class="ident">idx</span>, <span class="ident">value</span>) <span class="kw">in</span> <span class="kw-2">&amp;</span><span class="ident">arena</span> {
<span class="macro">println</span><span class="macro">!</span>(<span class="string">&quot;{:?} is at {:?}&quot;</span>, <span class="ident">value</span>, <span class="ident">idx</span>);
}</pre></div>
<h2 id="no_std" class="section-header"><a href="#no_std"><code>no_std</code></a></h2>
<p>To enable <code>no_std</code> compatibility, disable the on-by-default &quot;std&quot; feature. This
currently requires nightly Rust and <code>feature(alloc)</code> to get access to <code>Vec</code>.</p>
<pre><code class="language-toml">[dependencies]
generational-arena = { version = &quot;0.2&quot;, default-features = false }
</code></pre>
<h3 id="serialization-and-deserialization-with-serde" class="section-header"><a href="#serialization-and-deserialization-with-serde">Serialization and Deserialization with <a href="https://crates.io/crates/serde"><code>serde</code></a></a></h3>
<p>To enable serialization/deserialization support, enable the &quot;serde&quot; feature.</p>
<pre><code class="language-toml">[dependencies]
generational-arena = { version = &quot;0.2&quot;, features = [&quot;serde&quot;] }
</code></pre>
</div><h2 id='structs' class='section-header'><a href="#structs">Structs</a></h2>
<table><tr class='module-item'><td><a class="struct" href="struct.Arena.html" title='generational_arena::Arena struct'>Arena</a></td><td class='docblock-short'><p>The <code>Arena</code> allows inserting and removing elements that are referred to by
<code>Index</code>.</p>
</td></tr><tr class='module-item'><td><a class="struct" href="struct.Drain.html" title='generational_arena::Drain struct'>Drain</a></td><td class='docblock-short'><p>An iterator that removes elements from the arena.</p>
</td></tr><tr class='module-item'><td><a class="struct" href="struct.Index.html" title='generational_arena::Index struct'>Index</a></td><td class='docblock-short'><p>An index (and generation) into an <code>Arena</code>.</p>
</td></tr><tr class='module-item'><td><a class="struct" href="struct.IntoIter.html" title='generational_arena::IntoIter struct'>IntoIter</a></td><td class='docblock-short'><p>An iterator over the elements in an arena.</p>
</td></tr><tr class='module-item'><td><a class="struct" href="struct.Iter.html" title='generational_arena::Iter struct'>Iter</a></td><td class='docblock-short'><p>An iterator over shared references to the elements in an arena.</p>
</td></tr><tr class='module-item'><td><a class="struct" href="struct.IterMut.html" title='generational_arena::IterMut struct'>IterMut</a></td><td class='docblock-short'><p>An iterator over exclusive references to elements in this arena.</p>
</td></tr></table></section><section id="search" class="content hidden"></section><section class="footer"></section><aside id="help" class="hidden"><div><h1 class="hidden">Help</h1><div class="shortcuts"><h2>Keyboard Shortcuts</h2><dl><dt><kbd>?</kbd></dt><dd>Show this help dialog</dd><dt><kbd>S</kbd></dt><dd>Focus the search field</dd><dt><kbd></kbd></dt><dd>Move up in search results</dd><dt><kbd></kbd></dt><dd>Move down in search results</dd><dt><kbd></kbd></dt><dd>Switch tab</dd><dt><kbd>&#9166;</kbd></dt><dd>Go to active search result</dd><dt><kbd>+</kbd></dt><dd>Expand all sections</dd><dt><kbd>-</kbd></dt><dd>Collapse all sections</dd></dl></div><div class="infos"><h2>Search Tricks</h2><p>Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to restrict the search to a given type.</p><p>Accepted types are: <code>fn</code>, <code>mod</code>, <code>struct</code>, <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, and <code>const</code>.</p><p>Search functions by type signature (e.g., <code>vec -> usize</code> or <code>* -> vec</code>)</p><p>Search multiple things at once by splitting your query with comma (e.g., <code>str,u8</code> or <code>String,struct:Vec,test</code>)</p></div></div></aside><script>window.rootPath = "../";window.currentCrate = "generational_arena";</script><script src="../aliases.js"></script><script src="../main.js"></script><script defer src="../search-index.js"></script></body></html>