added main example

This commit is contained in:
Carl Fredrik Samson
2020-01-30 23:57:02 +01:00
parent 59f00d69e9
commit a84faa9f3f
15 changed files with 394 additions and 259 deletions

View File

@@ -13,7 +13,7 @@ before_script:
- cargo install-update -a
script:
- mdbook build ./ && mdbook test ./
- mdbook build ./ #&& mdbook test ./
deploy:
provider: pages

View File

@@ -247,6 +247,21 @@ really do is to stub out a <code>Reactor</code>, and <code>Executor</code> and i
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

View File

@@ -199,6 +199,21 @@ try to give a high level overview that will make it easier to learn Rusts
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

View File

@@ -350,6 +350,21 @@ one. <a href="https://github.com/async-rs/async-std">async std</a> and <a href="
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

View File

@@ -610,227 +610,6 @@ 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>
@@ -870,6 +649,21 @@ we're soon finished.</p>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

View File

@@ -145,7 +145,227 @@
<div id="content" class="content">
<main>
<h1><a class="header" href="#pin" id="pin">Pin</a></h1>
<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 mutable 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>
@@ -185,6 +405,21 @@
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

View File

@@ -145,7 +145,8 @@
<div id="content" class="content">
<main>
<pre><pre class="playpen"><code class="language-rust">use std::{
<pre><pre class="playpen"><code class="language-rust">
use std::{
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
thread::{self, JoinHandle}, time::{Duration, Instant}
@@ -153,9 +154,12 @@
fn main() {
let start = Instant::now();
// Many runtimes create a glocal `reactor` we pass it as an argument
let reactor = Reactor::new();
let reactor = Arc::new(Mutex::new(reactor));
let future1 = Task::new(reactor.clone(), 3, 1);
let future1 = Task::new(reactor.clone(), 2, 1);
let future2 = Task::new(reactor.clone(), 1, 2);
let fut1 = async {
@@ -171,10 +175,8 @@ fn main() {
};
let mainfut = async {
let handle1 = spawn(fut1);
let handle2 = spawn(fut2);
handle1.await;
handle2.await;
fut1.await;
fut2.await;
};
block_on(mainfut);
@@ -196,15 +198,6 @@ fn block_on&lt;F: Future&gt;(mut future: F) -&gt; F::Output {
val
}
fn spawn&lt;F: Future&gt;(future: F) -&gt; Pin&lt;Box&lt;F&gt;&gt; {
let mywaker = Arc::new(MyWaker{ thread: thread::current() });
let waker = waker_into_waker(Arc::into_raw(mywaker));
let mut cx = Context::from_waker(&amp;waker);
let mut boxed = Box::pin(future);
let _ = Future::poll(boxed.as_mut(), &amp;mut cx);
boxed
}
// ====================== FUTURE IMPLEMENTATION ==============================
#[derive(Clone)]
struct MyWaker {
@@ -384,6 +377,21 @@ impl Drop for Reactor {
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

View File

@@ -177,6 +177,21 @@
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

View File

@@ -239,6 +239,21 @@ really do is to stub out a <code>Reactor</code>, and <code>Executor</code> and i
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

View File

@@ -1080,13 +1080,13 @@ 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
In the <code>Drop</code> implementation you take a mutable 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>
<h1><a class="header" href="#pin-1" id="pin-1">Pin</a></h1>
<pre><pre class="playpen"><code class="language-rust">use std::{
<pre><pre class="playpen"><code class="language-rust">
use std::{
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
thread::{self, JoinHandle}, time::{Duration, Instant}
@@ -1094,9 +1094,12 @@ we're soon finished.</p>
fn main() {
let start = Instant::now();
// Many runtimes create a glocal `reactor` we pass it as an argument
let reactor = Reactor::new();
let reactor = Arc::new(Mutex::new(reactor));
let future1 = Task::new(reactor.clone(), 3, 1);
let future1 = Task::new(reactor.clone(), 2, 1);
let future2 = Task::new(reactor.clone(), 1, 2);
let fut1 = async {
@@ -1112,10 +1115,8 @@ fn main() {
};
let mainfut = async {
let handle1 = spawn(fut1);
let handle2 = spawn(fut2);
handle1.await;
handle2.await;
fut1.await;
fut2.await;
};
block_on(mainfut);
@@ -1137,15 +1138,6 @@ fn block_on&lt;F: Future&gt;(mut future: F) -&gt; F::Output {
val
}
fn spawn&lt;F: Future&gt;(future: F) -&gt; Pin&lt;Box&lt;F&gt;&gt; {
let mywaker = Arc::new(MyWaker{ thread: thread::current() });
let waker = waker_into_waker(Arc::into_raw(mywaker));
let mut cx = Context::from_waker(&amp;waker);
let mut boxed = Box::pin(future);
let _ = Future::poll(boxed.as_mut(), &amp;mut cx);
boxed
}
// ====================== FUTURE IMPLEMENTATION ==============================
#[derive(Clone)]
struct MyWaker {
@@ -1310,6 +1302,21 @@ impl Drop for Reactor {
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
[package]
name = "futures_example"
version = "0.1.0"
authors = ["Carl Fredrik Samson <cfsamson@gmail.com>"]
edition = "2018"

View File

View File

@@ -1,6 +1,6 @@
# Implementing our own Future
```rust
use std::{
future::Future, pin::Pin, sync::{mpsc::{channel, Sender}, Arc, Mutex},
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
@@ -192,4 +192,14 @@ impl Drop for Reactor {
self.handle.take().map(|h| h.join().unwrap()).unwrap();
}
}
```
```
> Unfortunately there seems to be a bug which causes a compiler error when
> trying to run code including the `async` keyword in Mdbook. I've filed an [issue
> for it][mdbook_issue] Until that is
> resolved you can test and run it in [the playground][playground_example].
[playground_example]:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ca43dba55c6e3838c5494de45875677f
[mdbook_issue]: https://github.com/rust-lang/mdBook/issues/1134