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