Article Directory
The standard library code is located at https://github.com/rust-lang/rust/tree/master/library
here using the latest version 1.45.2
Involved packages
std::future::*
Corresponding src/libstd/future.rs
, mainly provide the following api
pub use core::future::Future;
pub use core::future::{
from_generator, get_context, ResumeTy};
pub use core::future::{
pending, ready, Pending, Ready};
pub use core::future::IntoFuture;
core::future
Corresponding src/libcore/future
directory, there are the following files
future.rs
into_future.rs
mod.rs
pending.rs
poll_fn.rs
ready.rs
std::poll::*
withstd::wake::*
Corresponding to src/libcore/task/mod.rs, mainly provide the following api
mod poll;
pub use self::poll::Poll;
mod wake;
pub use self::wake::{
Context, RawWaker, RawWakerVTable, Waker};
src/libcore/task directory, there are the following files
mod.rs
poll.rs
wake.rs
Future
src/libcore/future/future.rs
#[lang = "future_trait"]
pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
The Future trait is the most basic trait of asynchronous programming. It has a poll method. The second parameter of poll is Context. Context contains a wake-up function. The poll method returns Poll::Ready or Poll::Pending.
Context
src/libcore/task/wake.rs
The context of asynchronous tasks is used by Future's poll method. Currently, only Waker is packaged internally. It is not ruled out that other things will be added in the future.
pub struct Context<'a> {
waker: &'a Waker,
_marker: PhantomData<fn(&'a ()) -> &'a ()>,
}
impl<'a> Context<'a> {
#[inline]
pub fn from_waker(waker: &'a Waker) -> Self {
Context {
waker, _marker: PhantomData }
}
#[inline]
pub fn waker(&self) -> &'a Waker {
&self.waker
}
}
Waker
src/libcore/task/wake.rs
The wake-up function is used to notify the executor that the task can run. It implements Send, Sync, and Clone, and encapsulates the RawWaker instance. RawWaker defines the specific wake-up behavior of the executor (generally use condition variables and mutex locks to implement wait and notify)
pub struct Waker {
waker: RawWaker,
}
impl Unpin for Waker {
}
unsafe impl Send for Waker {
}
unsafe impl Sync for Waker {
}
impl Clone for Waker {
fn clone(&self) -> Self {
Waker {
waker: unsafe {
(self.waker.vtable.clone)(self.waker.data) },
}
}
}
RawWaker
src/libcore/task/wake.rs
#[derive(PartialEq, Debug)]
pub struct RawWaker {
data: *const (),
vtable: &'static RawWakerVTable,
}
RawWakerVTable
src/libcore/task/wake.rs
A virtual function pointer table (vtable), used in RawWaker
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
clone: unsafe fn(*const ()) -> RawWaker,
wake: unsafe fn(*const ()),
wake_by_ref: unsafe fn(*const ()),
drop: unsafe fn(*const ()),
}
Poll
src/libcore/task/poll.rs
Future's poll method return value
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Poll<T> {
Ready(T),
Pending,
}
Ready
src/libcore/future/ready.rs
Create a Future with values ready immediately
#[derive(Debug, Clone)]
pub struct Ready<T>(Option<T>);
impl<T> Unpin for Ready<T> {
}
impl<T> Future for Ready<T> {
type Output = T;
#[inline]
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
Poll::Ready(self.0.take().expect("Ready polled after completion"))
}
}
pub fn ready<T>(t: T) -> Ready<T> {
Ready(Some(t))
}
eg
#![feature(future_readiness_fns)]
use core::future;
async fn run() {
let a = future::ready(1);
assert_eq!(a.await, 1);
}
Pending
src/libcore/future/pending.rs
Create a Future that can never be completed (calculated)
#[derive(Debug)]
pub struct Pending<T> {
_data: marker::PhantomData<T>,
}
pub fn pending<T>() -> Pending<T> {
Pending {
_data: marker::PhantomData }
}
impl<T> Future for Pending<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> {
Poll::Pending
}
}
eg
#![feature(future_readiness_fns)]
use core::future;
async fn run() {
let future = future::pending();
let () = future.await;
unreachable!();
}
IntoFuture
src/libcore/future/into_future.rs
Convert a type to Future
pub trait IntoFuture {
type Output;
type Future: Future<Output = Self::Output>;
fn into_future(self) -> Self::Future;
}
impl<F: Future> IntoFuture for F {
type Output = F::Output;
type Future = F;
fn into_future(self) -> Self::Future {
self
}
}
from_generator
src/libcore/future/mod.rs
- The ansyc code block is finally converted into a generator by the compiler. The generator will be wrapped in GenFuture. GenFuture implements Future. The resume method of the generator is called in poll. If it is in the state, it returns Poll::Pending, if it is Complete. (x), then return Poll::Ready(x)
- The meaning of ResumeTy: The generator cannot be implemented
for<'a, 'b> Generator<&'a mut Context<'b>>
, so a raw pointer is needed, and the raw pointer or NonNull cannot be combinedSend
withSync
#[derive(Debug, Copy, Clone)]
pub struct ResumeTy(NonNull<Context<'static>>);
unsafe impl Send for ResumeTy {
}
unsafe impl Sync for ResumeTy {
}
pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
where
T: Generator<ResumeTy, Yield = ()>,
{
struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {
}
impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
type Output = T::Return;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Safety:!Unpin + !Drop
let gen = unsafe {
Pin::map_unchecked_mut(self, |s| &mut s.0) };
match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
GeneratorState::Yielded(()) => Poll::Pending,
GeneratorState::Complete(x) => Poll::Ready(x),
}
}
}
GenFuture(gen)
}
pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
&mut *cx.0.as_ptr().cast()
}