Files
books-futures-explained/book/1_2_generators_pin.html
Carl Fredrik Samson 59f00d69e9 added main example
2020-01-30 21:02:37 +01:00

901 lines
38 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Generators and Pin - Futures Explained in 200 Lines of Rust</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body class="light">
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
document.body.className = theme;
document.querySelector('html').className = theme + ' js';
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<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" class="active"><strong aria-hidden="true">2.2.</strong> Generators and Pin</a></li><li><a href="1_3_pin.html"><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>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar" class="menu-bar">
<div id="menu-bar-sticky-container">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Futures Explained in 200 Lines of Rust</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1><a class="header" href="#generators-and-pin" id="generators-and-pin">Generators and Pin</a></h1>
<p>So the second difficult part that there seems to be a lot of questions about
is Generators and the <code>Pin</code> type.</p>
<h2><a class="header" href="#generators" id="generators">Generators</a></h2>
<blockquote>
<p><strong>Relevant for:</strong></p>
<ul>
<li>Understanding how the async/await syntax works since it's how <code>await</code> is implemented</li>
<li>Why we need <code>Pin</code></li>
<li>Why Rusts async model is extremely efficient</li>
</ul>
<p>The motivation for <code>Generators</code> can be found in <a href="https://github.com/rust-lang/rfcs/blob/master/text/2033-experimental-coroutines.md">RFC#2033</a>. It's very
well written and I can recommend reading through it (it talks as much about
async/await as it does about generators).</p>
</blockquote>
<p>Basically, there were three main options that were discussed when Rust was
desiging how the language would handle concurrency:</p>
<ol>
<li>Stackful coroutines, better known as green threads.</li>
<li>Using combinators.</li>
<li>Stackless coroutines, better known as generators.</li>
</ol>
<h3><a class="header" href="#stackful-coroutinesgreen-threads" id="stackful-coroutinesgreen-threads">Stackful coroutines/green threads</a></h3>
<p>I've written about green threads before. Go check out
<a href="https://cfsamson.gitbook.io/green-threads-explained-in-200-lines-of-rust/">Green Threads Explained in 200 lines of Rust</a> if you're interested.</p>
<p>Green threads uses the same mechanisms as an OS does by creating a thread for
each task, setting up a stack and forcing the CPU to save it's state and jump
from one task(thread) to another. We yield control to the scheduler which then
continues running a different task.</p>
<p>Rust had green threads once, but they were removed before it hit 1.0. The state
of execution is stored in each stack so in such a solution there would be no need
for <code>async</code>, <code>await</code>, <code>Futures</code> or <code>Pin</code>. All this would be implementation
details for the library.</p>
<h3><a class="header" href="#combinators" id="combinators">Combinators</a></h3>
<p><code>Futures 1.0</code> used combinators. If you've worked with <code>Promises</code> in JavaScript,
you already know combinators. In Rust they look like this:</p>
<pre><code class="language-rust noplaypen ignore">let future = Connection::connect(conn_str).and_then(|conn| {
conn.query(&quot;somerequest&quot;).map(|row|{
SomeStruct::from(row)
}).collect::&lt;Vec&lt;SomeStruct&gt;&gt;()
});
let rows: Result&lt;Vec&lt;SomeStruct&gt;, SomeLibraryError&gt; = block_on(future).unwrap();
</code></pre>
<p>While an effective solution there are mainly three downsides I'll focus on:</p>
<ol>
<li>The error messages produced could be extremely long and arcane</li>
<li>Not optimal memory usage</li>
<li>Did not allow to borrow across combinator steps.</li>
</ol>
<p>Point #3, is actually a major drawback with <code>Futures 1.0</code>.</p>
<p>Not allowing borrows across suspension points ends up being very
un-ergonomic and often requiring extra allocations or copying to accomplish
some tasks which is inefficient.</p>
<p>The reason for the higher than optimal memory usage is that this is basically
a callback-based approach, where each closure stores all the data it needs
for computation. This means that as we chain these, the memory required to store
the needed state increases with each added step.</p>
<h3><a class="header" href="#stackless-coroutinesgenerators" id="stackless-coroutinesgenerators">Stackless coroutines/generators</a></h3>
<p>This is the model used in Rust today. It a few notable advantages:</p>
<ol>
<li>It's easy to convert normal Rust code to a stackless corotuine using using
async/await as keywords (it can even be done using a macro).</li>
<li>No need for context switching and saving/restoring CPU state</li>
<li>No need to handle dynamic stack allocation</li>
<li>Very memory efficient</li>
<li>Allowed for borrows across suspension points</li>
</ol>
<p>The last point is in contrast to <code>Futures 1.0</code>. With async/await we can do this:</p>
<pre><code class="language-rust ignore">async fn myfn() {
let text = String::from(&quot;Hello world&quot;);
let borrowed = &amp;text[0..5];
somefuture.await;
println!(&quot;{}&quot;, borrowed);
}
</code></pre>
<p>Generators are implemented as state machines. The memory footprint of a chain
of computations is only defined by the largest footprint any single step
requires. That means that adding steps to a chain of computations might not
require any added memory at all.</p>
<h2><a class="header" href="#how-generators-work" id="how-generators-work">How generators work</a></h2>
<p>In Nightly Rust today you can use the <code>yield</code> keyword. Basically using this
keyword in a closure, converts it to a generator. A closure looking like this
(I'm going to use the terminology that's currently in Rust):</p>
<pre><code class="language-rust noplaypen ignore">let a = 4;
let b = move || {
println!(&quot;Hello&quot;);
yield a * 2;
println!(&quot;world!&quot;);
};
if let GeneratorState::Yielded(n) = gen.resume() {
println!(&quot;Got value {}&quot;, n);
}
if let GeneratorState::Complete(()) = gen.resume() {
()
};
</code></pre>
<p>Early on, before there was a consensus about the design of <code>Pin</code>, this
compiled to something looking similar to this:</p>
<pre><pre class="playpen"><code class="language-rust">fn main() {
let mut gen = GeneratorA::start(4);
if let GeneratorState::Yielded(n) = gen.resume() {
println!(&quot;Got value {}&quot;, n);
}
if let GeneratorState::Complete(()) = gen.resume() {
()
};
}
// If you've ever wondered why the parameters are called Y and R the naming from
// the original rfc most likely holds the answer
enum GeneratorState&lt;Y, R&gt; {
// originally called `CoResult`
Yielded(Y), // originally called `Yield(Y)`
Complete(R), // originally called `Return(R)`
}
trait Generator {
type Yield;
type Return;
fn resume(&amp;mut self) -&gt; GeneratorState&lt;Self::Yield, Self::Return&gt;;
}
enum GeneratorA {
Enter(i32),
Yield1(i32),
Exit,
}
impl GeneratorA {
fn start(a1: i32) -&gt; Self {
GeneratorA::Enter(a1)
}
}
impl Generator for GeneratorA {
type Yield = i32;
type Return = ();
fn resume(&amp;mut self) -&gt; GeneratorState&lt;Self::Yield, Self::Return&gt; {
// lets us get ownership over current state
match std::mem::replace(&amp;mut *self, GeneratorA::Exit) {
GeneratorA::Enter(a1) =&gt; {
/*|---code before yield1---|*/
/*|*/ println!(&quot;Hello&quot;); /*|*/
/*|*/ let a = a1 * 2; /*|*/
/*|------------------------|*/
*self = GeneratorA::Yield1(a);
GeneratorState::Yielded(a)
}
GeneratorA::Yield1(_) =&gt; {
/*|----code after yield1----|*/
/*|*/ println!(&quot;world!&quot;); /*|*/
/*|-------------------------|*/
*self = GeneratorA::Exit;
GeneratorState::Complete(())
}
GeneratorA::Exit =&gt; panic!(&quot;Can't advance an exited generator!&quot;),
}
}
}
</code></pre></pre>
<blockquote>
<p>The <code>yield</code> keyword was discussed first in <a href="https://github.com/rust-lang/rfcs/pull/1823">RFC#1823</a> and in <a href="https://github.com/rust-lang/rfcs/pull/1832">RFC#1832</a>.</p>
</blockquote>
<p>Now that you know that the <code>yield</code> keyword in reality rewrites your code to become a state machine,
you'll also know the basics of how <code>await</code> works. It's very similar.</p>
<p>Now, there are some limitations in our naive state machine above. What happens when you have a
<code>borrow</code> across a <code>yield</code> point?</p>
<p>We could forbid that, but <strong>one of the major design goals for the async/await syntax has been
to allow this</strong>. These kinds of borrows were not possible using <code>Futures 1.0</code> so we can't let this
limitation just slip and call it a day yet.</p>
<p>Instead of discussing it in theory, let's look at some code. </p>
<blockquote>
<p>We'll use the optimized version of the state machines which is used in Rust today. For a more
in deapth explanation see <a href="https://tmandry.gitlab.io/blog/posts/optimizing-await-1/">Tyler Mandry's execellent article: How Rust optimizes async/await</a></p>
</blockquote>
<pre><code class="language-rust noplaypen ignore">let a = 4;
let b = move || {
let to_borrow = String::new(&quot;Hello&quot;);
let borrowed = &amp;to_borrow;
println!(&quot;{}&quot;, borrowed);
yield a * 2;
println!(&quot;{} world!&quot;, borrowed);
};
</code></pre>
<p>Now what does our rewritten state machine look like with this example?</p>
<pre><pre class="playpen"><code class="language-rust compile_fail">
# #![allow(unused_variables)]
#fn main() {
# // If you've ever wondered why the parameters are called Y and R the naming from
# // the original rfc most likely holds the answer
# enum GeneratorState&lt;Y, R&gt; {
# // originally called `CoResult`
# Yielded(Y), // originally called `Yield(Y)`
# Complete(R), // originally called `Return(R)`
# }
#
# trait Generator {
# type Yield;
# type Return;
# fn resume(&amp;mut self) -&gt; GeneratorState&lt;Self::Yield, Self::Return&gt;;
# }
enum GeneratorA {
Enter,
Yield1 {
to_borrow: String,
borrowed: &amp;String, // uh, what lifetime should this have?
},
Exit,
}
# impl GeneratorA {
# fn start() -&gt; Self {
# GeneratorA::Enter
# }
# }
impl Generator for GeneratorA {
type Yield = usize;
type Return = ();
fn resume(&amp;mut self) -&gt; GeneratorState&lt;Self::Yield, Self::Return&gt; {
// lets us get ownership over current state
match std::mem::replace(&amp;mut *self, GeneratorA::Exit) {
GeneratorA::Enter =&gt; {
let to_borrow = String::from(&quot;Hello&quot;);
let borrowed = &amp;to_borrow;
*self = GeneratorA::Yield1 {to_borrow, borrowed};
GeneratorState::Yielded(borrowed.len())
}
GeneratorA::Yield1 {to_borrow, borrowed} =&gt; {
println!(&quot;Hello {}&quot;, borrowed);
*self = GeneratorA::Exit;
GeneratorState::Complete(())
}
GeneratorA::Exit =&gt; panic!(&quot;Can't advance an exited generator!&quot;),
}
}
}
#}</code></pre></pre>
<p>If you try to compile this you'll get an error (just try it yourself by pressing play).</p>
<p>What is the lifetime of <code>&amp;String</code>. It's not the same as the lifetime of <code>Self</code>. It's not <code>static</code>.
Turns out that it's not possible for us in Rusts syntax to describe this lifetime, which means, that
to make this work, we'll have to let the compiler know that <em>we</em> control this correct.</p>
<p>That means turning to unsafe.</p>
<p>Let's try to write an implementation that will compiler using <code>unsafe</code>. As you'll
see we end up in a <em>self referential struct</em>. A struct which holds references
into itself.</p>
<p>As you'll notice, this compiles just fine!</p>
<pre><pre class="playpen"><code class="language-rust editable">pub fn main() {
let mut gen = GeneratorA::start();
let mut gen2 = GeneratorA::start();
if let GeneratorState::Yielded(n) = gen.resume() {
println!(&quot;Got value {}&quot;, n);
}
// If you uncomment this, very bad things can happen. This is why we need `Pin`
// std::mem::swap(&amp;mut gen, &amp;mut gen2);
if let GeneratorState::Yielded(n) = gen2.resume() {
println!(&quot;Got value {}&quot;, n);
}
// if you uncomment `mem::swap`.. this should now start gen2.
if let GeneratorState::Complete(()) = gen.resume() {
()
};
}
enum GeneratorState&lt;Y, R&gt; {
Yielded(Y), // originally called `Yield(Y)`
Complete(R), // originally called `Return(R)`
}
trait Generator {
type Yield;
type Return;
fn resume(&amp;mut self) -&gt; GeneratorState&lt;Self::Yield, Self::Return&gt;;
}
enum GeneratorA {
Enter,
Yield1 {
to_borrow: String,
borrowed: *const String, // Normally you'll see `std::ptr::NonNull` used instead of *ptr
},
Exit,
}
impl GeneratorA {
fn start() -&gt; Self {
GeneratorA::Enter
}
}
impl Generator for GeneratorA {
type Yield = usize;
type Return = ();
fn resume(&amp;mut self) -&gt; GeneratorState&lt;Self::Yield, Self::Return&gt; {
// lets us get ownership over current state
match self {
GeneratorA::Enter =&gt; {
let to_borrow = String::from(&quot;Hello&quot;);
let borrowed = &amp;to_borrow;
let res = borrowed.len();
// Tricks to actually get a self reference
*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};
match self {
GeneratorA::Yield1{to_borrow, borrowed} =&gt; *borrowed = to_borrow,
_ =&gt; ()
};
GeneratorState::Yielded(res)
}
GeneratorA::Yield1 {borrowed, ..} =&gt; {
let borrowed: &amp;String = unsafe {&amp;**borrowed};
println!(&quot;{} world&quot;, borrowed);
*self = GeneratorA::Exit;
GeneratorState::Complete(())
}
GeneratorA::Exit =&gt; panic!(&quot;Can't advance an exited generator!&quot;),
}
}
}
</code></pre></pre>
<blockquote>
<p>Try to uncomment the line with <code>mem::swap</code> and see the result of running this code.</p>
</blockquote>
<p>While the example above compiles just fine, we expose users of this code to
both possible undefined behavior and other memory errors while using just safe
Rust. This is a big problem!</p>
<p>But now, let's prevent the segfault from happening using <code>Pin</code>. We'll discuss
<code>Pin</code> more below, but you'll get an introduction here by just reading the
comments.</p>
<pre><pre class="playpen"><code class="language-rust editable">#![feature(optin_builtin_traits)]
use std::pin::Pin;
pub fn main() {
let gen1 = GeneratorA::start();
let gen2 = GeneratorA::start();
// Before we pin the pointers, this is safe to do
// std::mem::swap(&amp;mut gen, &amp;mut gen2);
// constructing a `Pin::new()` on a type which does not implement `Unpin` is unsafe.
// However, as I mentioned in the start of the next chapter about `Pin` a
// boxed type automatically implements `Unpin` so to stay in safe Rust we can use
// that to avoid unsafe. You can also use crates like `pin_utils` to do this safely,
// just remember that they use unsafe under the hood so it's like using an already-reviewed
// unsafe implementation.
let mut pinned1 = Box::pin(gen1);
let mut pinned2 = Box::pin(gen2);
// Uncomment these if you think it's safe to pin the values to the stack instead
// (it is in this case). Remember to comment out the two previous lines first.
//let mut pinned1 = unsafe { Pin::new_unchecked(&amp;mut gen1) };
//let mut pinned2 = unsafe { Pin::new_unchecked(&amp;mut gen2) };
if let GeneratorState::Yielded(n) = pinned1.as_mut().resume() {
println!(&quot;Got value {}&quot;, n);
}
if let GeneratorState::Yielded(n) = pinned2.as_mut().resume() {
println!(&quot;Gen2 got value {}&quot;, n);
};
// This won't work
// std::mem::swap(&amp;mut gen, &amp;mut gen2);
// This will work but will just swap the pointers. Nothing inherently bad happens here.
// std::mem::swap(&amp;mut pinned1, &amp;mut pinned2);
let _ = pinned1.as_mut().resume();
let _ = pinned2.as_mut().resume();
}
enum GeneratorState&lt;Y, R&gt; {
// originally called `CoResult`
Yielded(Y), // originally called `Yield(Y)`
Complete(R), // originally called `Return(R)`
}
trait Generator {
type Yield;
type Return;
fn resume(self: Pin&lt;&amp;mut Self&gt;) -&gt; GeneratorState&lt;Self::Yield, Self::Return&gt;;
}
enum GeneratorA {
Enter,
Yield1 {
to_borrow: String,
borrowed: *const String, // Normally you'll see `std::ptr::NonNull` used instead of *ptr
},
Exit,
}
impl GeneratorA {
fn start() -&gt; Self {
GeneratorA::Enter
}
}
// This tells us that the underlying pointer is not safe to move after pinning. In this case,
// only we as implementors &quot;feel&quot; this, however, if someone is relying on our Pinned pointer
// this will prevent them from moving it. You need to enable the feature flag
// `#![feature(optin_builtin_traits)]` and use the nightly compiler to implement `!Unpin`.
// Normally, you would use `std::marker::PhantomPinned` to indicate that the
// struct is `!Unpin`.
impl !Unpin for GeneratorA { }
impl Generator for GeneratorA {
type Yield = usize;
type Return = ();
fn resume(self: Pin&lt;&amp;mut Self&gt;) -&gt; GeneratorState&lt;Self::Yield, Self::Return&gt; {
// lets us get ownership over current state
let this = unsafe { self.get_unchecked_mut() };
match this {
GeneratorA::Enter =&gt; {
let to_borrow = String::from(&quot;Hello&quot;);
let borrowed = &amp;to_borrow;
let res = borrowed.len();
// Trick to actually get a self reference. We can't reference
// the `String` earlier since these references will point to the
// location in this stack frame which will not be valid anymore
// when this function returns.
*this = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};
match this {
GeneratorA::Yield1{to_borrow, borrowed} =&gt; *borrowed = to_borrow,
_ =&gt; ()
};
GeneratorState::Yielded(res)
}
GeneratorA::Yield1 {borrowed, ..} =&gt; {
let borrowed: &amp;String = unsafe {&amp;**borrowed};
println!(&quot;{} world&quot;, borrowed);
*this = GeneratorA::Exit;
GeneratorState::Complete(())
}
GeneratorA::Exit =&gt; panic!(&quot;Can't advance an exited generator!&quot;),
}
}
}
</code></pre></pre>
<p>Now, as you see, the user of this code must either:</p>
<ol>
<li>Box the value and thereby allocating it on the heap</li>
<li>Use <code>unsafe</code> and pin the value to the stack. The user knows that if they move
the value afterwards it will violate the guarantee they promise to uphold when
they did their unsafe implementation.</li>
</ol>
<p>Now, the code which is created and the need for <code>Pin</code> to allow for borrowing
across <code>yield</code> points should be pretty clear. </p>
<h2><a class="header" href="#pin" id="pin">Pin</a></h2>
<blockquote>
<p><strong>Relevant for</strong></p>
<ol>
<li>To understand <code>Generators</code> and <code>Futures</code></li>
<li>Knowing how to use <code>Pin</code> is required when implementing your own <code>Future</code></li>
<li>To understand self-referential types in Rust</li>
<li>This is the way borrowing across <code>await</code> points is accomplished</li>
</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>
<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>
<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 &quot;unsafe&quot;, 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>
<p>Let's take a look at an example:</p>
<pre><pre class="playpen"><code class="language-rust editable">use std::pin::Pin;
fn main() {
let mut test1 = Test::new(&quot;test1&quot;);
test1.init();
let mut test2 = Test::new(&quot;test2&quot;);
test2.init();
println!(&quot;a: {}, b: {}&quot;, test1.a(), test1.b());
std::mem::swap(&amp;mut test1, &amp;mut test2); // try commenting out this line
println!(&quot;a: {}, b: {}&quot;, test2.a(), test2.b());
}
#[derive(Debug)]
struct Test {
a: String,
b: *const String,
}
impl Test {
fn new(txt: &amp;str) -&gt; Self {
let a = String::from(txt);
Test {
a,
b: std::ptr::null(),
}
}
fn init(&amp;mut self) {
let self_ref: *const String = &amp;self.a;
self.b = self_ref;
}
fn a(&amp;self) -&gt; &amp;str {
&amp;self.a
}
fn b(&amp;self) -&gt; &amp;String {
unsafe {&amp;*(self.b)}
}
}
</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>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;
pub fn main() {
let mut test1 = Test::new(&quot;test1&quot;);
test1.init();
let mut test1_pin = unsafe { Pin::new_unchecked(&amp;mut test1) };
let mut test2 = Test::new(&quot;test2&quot;);
test2.init();
let mut test2_pin = unsafe { Pin::new_unchecked(&amp;mut test2) };
println!(
&quot;a: {}, b: {}&quot;,
Test::a(test1_pin.as_ref()),
Test::b(test1_pin.as_ref())
);
// Try to uncomment this and see what happens
// std::mem::swap(test1_pin.as_mut(), test2_pin.as_mut());
println!(
&quot;a: {}, b: {}&quot;,
Test::a(test2_pin.as_ref()),
Test::b(test2_pin.as_ref())
);
}
#[derive(Debug)]
struct Test {
a: String,
b: *const String,
_marker: PhantomPinned,
}
impl Test {
fn new(txt: &amp;str) -&gt; Self {
let a = String::from(txt);
Test {
a,
b: std::ptr::null(),
// This makes our type `!Unpin`
_marker: PhantomPinned,
}
}
fn init(&amp;mut self) {
let self_ptr: *const String = &amp;self.a;
self.b = self_ptr;
}
fn a&lt;'a&gt;(self: Pin&lt;&amp;'a Self&gt;) -&gt; &amp;'a str {
&amp;self.get_ref().a
}
fn b&lt;'a&gt;(self: Pin&lt;&amp;'a Self&gt;) -&gt; &amp;'a String {
unsafe { &amp;*(self.b) }
}
}
</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>
<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>
<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 &quot;self&quot; is invalidated.</p>
<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;
pub fn main() {
let mut test1 = Test::new(&quot;test1&quot;);
let mut test2 = Test::new(&quot;test2&quot;);
println!(&quot;a: {}, b: {}&quot;,test1.as_ref().a(), test1.as_ref().b());
// Try to uncomment this and see what happens
// std::mem::swap(&amp;mut test1, &amp;mut test2);
println!(&quot;a: {}, b: {}&quot;,test2.as_ref().a(), test2.as_ref().b());
}
#[derive(Debug)]
struct Test {
a: String,
b: *const String,
_marker: PhantomPinned,
}
impl Test {
fn new(txt: &amp;str) -&gt; Pin&lt;Box&lt;Self&gt;&gt; {
let a = String::from(txt);
let t = Test {
a,
b: std::ptr::null(),
_marker: PhantomPinned,
};
let mut boxed = Box::pin(t);
let self_ptr: *const String = &amp;boxed.as_ref().a;
unsafe { boxed.as_mut().get_unchecked_mut().b = self_ptr };
boxed
}
fn a&lt;'a&gt;(self: Pin&lt;&amp;'a Self&gt;) -&gt; &amp;'a str {
&amp;self.get_ref().a
}
fn b&lt;'a&gt;(self: Pin&lt;&amp;'a Self&gt;) -&gt; &amp;'a String {
unsafe { &amp;*(self.b) }
}
}
</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&lt;'a, T&gt; is entirely equivalent to &amp;'a mut T.</li>
<li>Getting a <code>&amp;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>
<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>
<p>In short, projection is using a field on your type. <code>mystruct.field1</code> is a
projection. Structural pinning is using <code>Pin</code> on struct fields. This has several
caveats and is not something you'll normally see so I refer to the documentation
for that.</p>
<h3><a class="header" href="#pin-and-drop" id="pin-and-drop">Pin and Drop</a></h3>
<p>The <code>Pin</code> guarantee exists from the moment the value is pinned until it's dropped.
In the <code>Drop</code> implementation you take a mutabl reference to <code>self</code>, which means
extra care must be taken when implementing <code>Drop</code> for pinned types.</p>
<h2><a class="header" href="#putting-it-all-together" id="putting-it-all-together">Putting it all together</a></h2>
<p>This is exactly what we'll do when we implement our own <code>Futures</code> stay tuned,
we're soon finished.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="1_1_trait_objects.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="1_3_pin.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="1_1_trait_objects.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a href="1_3_pin.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>