Output
type is whatever the future producesPin
is a memory safety typeContext
is a generic way for the runtime to provide … context :)pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
A simple future which will never complete
use core::{future::Future, pin::Pin, task::{Context, Poll}};
pub struct Never;
impl Future for Never {
type Output = ();
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> {
Poll::Pending
}
}
A simple future which will immediately complete
use core::{future::Future, pin::Pin, task::{Context, Poll}};
pub struct Always;
impl Future for Always {
type Output = ();
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> {
Poll::Ready(())
}
}
async-std
cargo run --bin 01_never
use future_anatomy::never::*;
#[async_std::main]
async fn main() {
let _ = MyFuture.await; // blocks forever
}
Pin
?Pin
removes the ability for a type to be moved so that self-references remain validlet sql: String = format!("SELECT FROM users WHERE usersname = {}", user);
let db_resp = self.query(&sql).await;
let sql: String = format!("SELECT FROM users WHERE usersname = {}", user);
let db_resp = self.query(&sql).await; // <-- creates a 'DbFuture' behind the scenes
let sql: String = format!("SELECT FROM users WHERE usersname = {}", user);
let db_resp = self.query(&sql).await;
true
on first pollPoll::Ready(())
on second polluse core::{future::Future,pin::Pin,task::{Context, Poll}};
pub struct Twice(bool);
impl Twice {
pub fn new() -> Self {
Self(false)
}
}
impl Future for Twice {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> {
if self.0 {
dbg!(Poll::Ready(()))
} else {
self.0 = true;
dbg!(Poll::Pending)
}
}
}
❤ (tempest) ~/P/t/t/d/e/01-future-anatomy> cargo run --bin 02_twice
Compiling 01-future-anatomy v0.1.0 (/home/Projects/talks/teaching-rust/dd-async/exercises/01-future-anatomy)
Finished dev [unoptimized + debuginfo] target(s) in 0.69s
Running `target/debug/02_twice`
[src/twice.rs:17] Poll::Pending = Pending
use core::{future::Future,pin::Pin,task::{Context, Poll}};
pub struct Twice(bool);
impl Twice {
pub fn new() -> Self {
Self(false)
}
}
impl Future for Twice {
type Output = ();
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<()> {
if self.0 {
Poll::Ready(())
} else {
self.0 = true;
ctx.waker().wake_by_ref();
Poll::Pending
}
}
}
❤ (tempest) ~/P/t/t/d/e/01-future-anatomy> cargo run --bin 03_twice
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/03_twice`
Future says: ()
Async/ Await are relatively modern and hide what Futures look like under the hood
use async_std::{fs::File, io::Read};
async fn read_file(path: &str) -> std::io::Result<String> {
let mut f = File::open(path).await?;
let mut buf = String::new();
f.read_to_string(&mut buf).await?;
Ok(buf)
}
Async/ Await are relatively modern and hide what Futures look like under the hood
use async_std::{fs::File, io::Read};
fn read_file(path: &str) -> impl Future<Output=std::io::Result<String>> {
async {
let mut f = File::open(path).await?;
let mut buf = String::new();
f.read_to_string(&mut buf).await?;
Ok(buf)
}
}
Await
the end of all things.await
gets desugared by the compiler