First commit.
This commit is contained in:
commit
281d75ced9
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async_tests"
|
||||||
|
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "async_tests"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
110
src/main.rs
Normal file
110
src/main.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
//! Experiments in manually polling and yielding from Futures.
|
||||||
|
//!
|
||||||
|
//! The idea here is that Futures are a really convenient way to write state
|
||||||
|
//! machines that progressively do computations. However, the whole async
|
||||||
|
//! ecosystem so far seems to be built on the following assumptions:
|
||||||
|
//!
|
||||||
|
//! 1. async code is primarily meant for yielding on IO, not for doing
|
||||||
|
//! computations in a controlled iterative way.
|
||||||
|
//! 2. Polling async code should be done by "executors" rather than manually.
|
||||||
|
//!
|
||||||
|
//! Below is an example of using async outside of those assumptions. In
|
||||||
|
//! this case, we have async code that never does any IO, and is purely
|
||||||
|
//! doing computations. But it does those computations *progressively*, with
|
||||||
|
//! yield points to allow other code to run, and manual polling to move the
|
||||||
|
//! computation along as desired.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
future::Future,
|
||||||
|
pin::{pin, Pin},
|
||||||
|
task::Context,
|
||||||
|
task::Poll,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// These are just examples of using the APIs further down in the file.
|
||||||
|
|
||||||
|
// Polling an async function.
|
||||||
|
let mut b = pin!(foo(8));
|
||||||
|
loop {
|
||||||
|
match poll(&mut b) {
|
||||||
|
Poll::Ready(v) => {
|
||||||
|
println!("{}", v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Poll::Pending => println!("Not yet!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polling an async block that captures things.
|
||||||
|
let mut x = 5;
|
||||||
|
let y = &mut x;
|
||||||
|
let mut f = pin!(async move {
|
||||||
|
for _ in 0..10 {
|
||||||
|
*y += 1;
|
||||||
|
pause().await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
loop {
|
||||||
|
match poll(&mut f) {
|
||||||
|
Poll::Ready(_) => {
|
||||||
|
println!("{}", x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Poll::Pending => println!("Not yet!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn foo(a: i32) -> i32 {
|
||||||
|
let mut b = 26;
|
||||||
|
for _ in 0..10 {
|
||||||
|
b += a;
|
||||||
|
pause().await;
|
||||||
|
}
|
||||||
|
b
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------
|
||||||
|
|
||||||
|
/// If awaited, will yield control to the executor immediately.
|
||||||
|
pub fn pause() -> Pause {
|
||||||
|
Pause { first_time: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A future that simply yields to the executor.
|
||||||
|
pub struct Pause {
|
||||||
|
first_time: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Future for Pause {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
if self.first_time {
|
||||||
|
self.as_mut().first_time = false;
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
Poll::Pending
|
||||||
|
} else {
|
||||||
|
Poll::Ready(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Polls a future once, without a waker.
|
||||||
|
pub fn poll<F: Future + Unpin>(future: F) -> Poll<F::Output> {
|
||||||
|
use std::task::{RawWaker, RawWakerVTable, Waker};
|
||||||
|
|
||||||
|
// TODO: replace with `std::task::Waker::noop()` if/when it
|
||||||
|
// lands on stable Rust.
|
||||||
|
let noop_waker = {
|
||||||
|
const VTABLE: RawWakerVTable = RawWakerVTable::new(|_| RAW, |_| {}, |_| {}, |_| {});
|
||||||
|
const RAW: RawWaker = RawWaker::new(std::ptr::null(), &VTABLE);
|
||||||
|
unsafe { Waker::from_raw(RAW) }
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut context = Context::from_waker(&noop_waker);
|
||||||
|
pin!(future).poll(&mut context)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user