finished all but the main example
This commit is contained in:
@@ -78,7 +78,7 @@
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div class="sidebar-scrollbox">
|
||||
<ol class="chapter"><li><a href="0_0_introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="1_0_background_information.html"><strong aria-hidden="true">2.</strong> Some background information</a></li><li><ol class="section"><li><a href="1_1_trait_objects.html"><strong aria-hidden="true">2.1.</strong> Trait objects and fat pointers</a></li><li><a href="1_2_generators_pin.html"><strong aria-hidden="true">2.2.</strong> Generators and Pin</a></li><li><a href="1_3_pin.html" class="active"><strong aria-hidden="true">2.3.</strong> Pin</a></li></ol></li><li><a href="2_0_future_example.html"><strong aria-hidden="true">3.</strong> The main example</a></li><li><a href="2_1_concurrent_futures.html"><strong aria-hidden="true">4.</strong> Bonus 1: concurrent futures</a></li></ol>
|
||||
<ol class="chapter"><li><a href="0_0_introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="1_0_background_information.html"><strong aria-hidden="true">2.</strong> Some background information</a></li><li><a href="1_1_trait_objects.html"><strong aria-hidden="true">3.</strong> Trait objects and fat pointers</a></li><li><a href="1_2_generators_pin.html"><strong aria-hidden="true">4.</strong> Generators and Pin</a></li><li><a href="1_3_pin.html" class="active"><strong aria-hidden="true">5.</strong> Pin</a></li><li><a href="1_4_reactor_executor.html"><strong aria-hidden="true">6.</strong> Reactor/Executor Pattern</a></li><li><a href="2_0_future_example.html"><strong aria-hidden="true">7.</strong> The main example</a></li><li><a href="2_1_concurrent_futures.html"><strong aria-hidden="true">8.</strong> Bonus 1: concurrent futures</a></li></ol>
|
||||
</div>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||
</nav>
|
||||
@@ -145,7 +145,7 @@
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h2><a class="header" href="#pin" id="pin">Pin</a></h2>
|
||||
<h1><a class="header" href="#pin" id="pin">Pin</a></h1>
|
||||
<blockquote>
|
||||
<p><strong>Relevant for</strong></p>
|
||||
<ol>
|
||||
@@ -156,23 +156,60 @@
|
||||
</ol>
|
||||
<p><code>Pin</code> was suggested in <a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">RFC#2349</a></p>
|
||||
</blockquote>
|
||||
<p>Ping consists of the <code>Pin</code> type and the <code>Unpin</code> marker. Let's start off with some general rules:</p>
|
||||
<p>We already got a brief introduction of <code>Pin</code> in the previous chapters, so we'll
|
||||
start off here with some definitions and a set of rules to remember.</p>
|
||||
<h2><a class="header" href="#definitions" id="definitions">Definitions</a></h2>
|
||||
<p>Pin consists of the <code>Pin</code> type and the <code>Unpin</code> marker. Pin's purpose in life is
|
||||
to govern the rules that need to apply for types which implement <code>!Unpin</code>.</p>
|
||||
<p>Pin is only relevant for pointers. A reference to an object is a pointer.</p>
|
||||
<p>Yep, that's double negation for you, as in "does-not-implement-unpin". For this
|
||||
chapter and only this chapter we'll rename these markers to:</p>
|
||||
<blockquote>
|
||||
<p><code>!Unpin</code> = <code>MustStay</code> and <code>Unpin</code> = <code>CanMove</code></p>
|
||||
</blockquote>
|
||||
<p>It just makes it so much easier to understand them.</p>
|
||||
<h2><a class="header" href="#rules-to-remember" id="rules-to-remember">Rules to remember</a></h2>
|
||||
<ol>
|
||||
<li>Pin does nothing special, it only prevents the user of an API to violate some assumtions you make when writing your (most likely) unsafe code.</li>
|
||||
<li>Most standard library types implement <code>Unpin</code></li>
|
||||
<li><code>Unpin</code> means it's OK for this type to be moved even when pinned.</li>
|
||||
<li>If you <code>Box</code> a value, that boxed value automatcally implements <code>Unpin</code>.</li>
|
||||
<li>The main use case for <code>Pin</code> is to allow self referential types</li>
|
||||
<li>The implementation behind objects that doens't implement <code>Unpin</code> is most likely unsafe
|
||||
<ol>
|
||||
<li><code>Pin</code> prevents users from your code to break the assumtions you make when writing the <code>unsafe</code> implementation</li>
|
||||
<li>It doesn't solve the fact that you'll have to write unsafe code to actually implement it</li>
|
||||
</ol>
|
||||
<li>
|
||||
<p>If <code>T: CanMove</code> (which is the default), then <code>Pin<'a, T></code> is entirely equivalent to <code>&'a mut T</code>. in other words: <code>CanMove</code> means it's OK for this type to be moved even when pinned, so <code>Pin</code> will have no effect on such a type.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Getting a <code>&mut T</code> to a pinned pointer requires unsafe if <code>T: MustStay</code>. In other words: requiring a pinned pointer to a type which is <code>MustStay</code> prevents the <em>user</em> of that API from moving that value unless it choses to write <code>unsafe</code> code.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Pinning does nothing special with that memory like putting it into some "read only" memory or anything fancy. It only tells the compiler that some operations on this value should be forbidden. </p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Most standard library types implement <code>CanMove</code>. The same goes for most
|
||||
"normal" types you encounter in Rust. <code>Futures</code> and <code>Generators</code> are two
|
||||
exceptions.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The main use case for <code>Pin</code> is to allow self referential types, the whole
|
||||
justification for stabilizing them was to allow that. There are still corner
|
||||
cases in the API which are being explored.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The implementation behind objects that are <code>MustStay</code> is most likely unsafe.
|
||||
Moving such a type can cause the universe to crash. As of the time of writing
|
||||
this book, creating an reading fields of a self referential struct still requires <code>unsafe</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You're not really meant to be implementing <code>MustStay</code>, but you can on nightly with a feature flag, or by adding <code>std::marker::PhantomPinned</code> to your type.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>When Pinning, you can either pin a value to memory either on the stack or
|
||||
on the heap.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Pinning a <code>MustStay</code> pointer to the stack requires <code>unsafe</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Pinning a <code>MustStay</code> pointer to the heap does not require <code>unsafe</code>. There is a shortcut for doing this using <code>Box::pin</code>.</p>
|
||||
</li>
|
||||
<li>You're not really meant to be implementing <code>!Unpin</code>, but you can on nightly with a feature flag</li>
|
||||
</ol>
|
||||
<blockquote>
|
||||
<p>Unsafe code does not mean it's litterally "unsafe", it only relieves the
|
||||
<p>Unsafe code does not mean it's literally "unsafe", it only relieves the
|
||||
guarantees you normally get from the compiler. An <code>unsafe</code> implementation can
|
||||
be perfectly safe to do, but you have no safety net.</p>
|
||||
</blockquote>
|
||||
@@ -220,11 +257,30 @@ impl Test {
|
||||
}
|
||||
}
|
||||
</code></pre></pre>
|
||||
<p>As you can see this results in unwanted behavior. The pointer to <code>b</code> stays the
|
||||
same and points to the old value. It's easy to get this to segfault, and fail
|
||||
in other spectacular ways as well.</p>
|
||||
<p>Pin essentially prevents the <strong>user</strong> of your unsafe code
|
||||
(even if that means yourself) move the value after it's pinned.</p>
|
||||
<p>Let's walk through this example since we'll be using it the rest of this chapter.</p>
|
||||
<p>We have a self-referential struct <code>Test</code>. <code>Test</code> needs an <code>init</code> method to be
|
||||
created which is strange but we'll need that to keep this example as short as
|
||||
possible.</p>
|
||||
<p><code>Test</code> provides two methods to get a reference to the value of the fields
|
||||
<code>a</code> and <code>b</code>. Since <code>b</code> is a reference to <code>a</code> we store it as a pointer since
|
||||
the borrowing rules of Rust doesn't allow us to define this lifetime.</p>
|
||||
<p>In our main method we first instantiate two instances of <code>Test</code> and print out
|
||||
the value of the fields on <code>test1</code>. We get:</p>
|
||||
<pre><code class="language-rust ignore">a: test1, b: test1
|
||||
</code></pre>
|
||||
<p>Next we swap the data stored at the memory location which <code>test1</code> is pointing to
|
||||
with the data stored at the memory location <code>test2</code> is pointing to and vice a verca.</p>
|
||||
<p>We should expect that printing the fields of <code>test2</code> should display the same as
|
||||
<code>test1</code> (since the object we printed before the swap has moved there now).</p>
|
||||
<pre><code class="language-rust ignore">a: test1, b: test2
|
||||
</code></pre>
|
||||
<p>The pointer to <code>b</code> still points to the old location. That location is now
|
||||
occupied with the string "test2". This can be a bit hard to visualize so I made
|
||||
a figure that i hope can help.</p>
|
||||
<p><strong>Fig 1: Before and after swap</strong>
|
||||
<img src="../assets/swap_problem.jpg" alt="swap_problem" /></p>
|
||||
<p>As you can see this results in unwanted behavior. It's easy to get this to
|
||||
segfault, show UB and fail in other spectacular ways as well.</p>
|
||||
<p>If we change the example to using <code>Pin</code> instead:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust editable">use std::pin::Pin;
|
||||
use std::marker::PhantomPinned;
|
||||
@@ -286,13 +342,14 @@ impl Test {
|
||||
|
||||
</code></pre></pre>
|
||||
<p>Now, what we've done here is pinning a stack address. That will always be
|
||||
<code>unsafe</code> if our type implements <code>!Unpin</code>, in other words. That our type is not
|
||||
<code>Unpin</code> which is the norm.</p>
|
||||
<code>unsafe</code> if our type implements <code>!Unpin</code> (aka <code>MustStay</code>). </p>
|
||||
<p>We use some tricks here, including requiring an <code>init</code>. If we want to fix that
|
||||
and let users avoid <code>unsafe</code> we need to place our data on the heap.</p>
|
||||
and let users avoid <code>unsafe</code> we need to pin our data on the heap instead.</p>
|
||||
<blockquote>
|
||||
<p>Stack pinning will always depend on the current stack frame we're in, so we
|
||||
can't create a self referential object in one stack frame and return it since
|
||||
any pointers we take to "self" is invalidated.</p>
|
||||
</blockquote>
|
||||
<p>The next example solves some of our friction at the cost of a heap allocation.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust editbable">use std::pin::Pin;
|
||||
use std::marker::PhantomPinned;
|
||||
@@ -339,19 +396,10 @@ impl Test {
|
||||
}
|
||||
}
|
||||
</code></pre></pre>
|
||||
<p>Seeing this we're ready to sum up with a few more points to remember about
|
||||
pinning:</p>
|
||||
<ol>
|
||||
<li>Pinning only makes sense to do for types that are <code>!Unpin</code></li>
|
||||
<li>Pinning a <code>!Unpin</code> pointer to the stack will requires <code>unsafe</code></li>
|
||||
<li>Pinning a boxed value will not require <code>unsafe</code>, even if the type is <code>!Unpin</code></li>
|
||||
<li>If T: Unpin (which is the default), then Pin<'a, T> is entirely equivalent to &'a mut T.</li>
|
||||
<li>Getting a <code>&mut T</code> to a pinned pointer requires unsafe if <code>T: !Unpin</code></li>
|
||||
<li>Pinning is really only useful when implementing self-referential types.<br />
|
||||
For all intents and purposes you can think of <code>!Unpin</code> = self-referential-type</li>
|
||||
</ol>
|
||||
<p>The fact that boxing (heap allocating) a value that implements <code>!Unpin</code> is safe
|
||||
makes sense. Once the data is allocated on the heap it will have a stable address. </p>
|
||||
makes sense. Once the data is allocated on the heap it will have a stable address.</p>
|
||||
<p>There is no need for us as users of the API to take special care and ensure
|
||||
that the self-referential pointer stays valid.</p>
|
||||
<p>There are ways to safely give some guarantees on stack pinning as well, but right
|
||||
now you need to use a crate like <a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">pin_utils</a>:<a href="https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md">pin_utils</a> to do that.</p>
|
||||
<h3><a class="header" href="#projectionstructural-pinning" id="projectionstructural-pinning">Projection/structural pinning</a></h3>
|
||||
@@ -378,7 +426,7 @@ we're soon finished.</p>
|
||||
|
||||
|
||||
|
||||
<a rel="next" href="2_0_future_example.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next" href="1_4_reactor_executor.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -396,7 +444,7 @@ we're soon finished.</p>
|
||||
|
||||
|
||||
|
||||
<a href="2_0_future_example.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a href="1_4_reactor_executor.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user