Created
February 6, 2022 22:42
-
-
Save robertohuertasm/5c6a868f94b432f158c0793fa795ced2 to your computer and use it in GitHub Desktop.
Playing with Pin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use pin_project::pin_project; | |
use std::future::Future; | |
use std::pin::Pin; | |
use std::task; | |
use std::time::Duration; | |
use tokio::time::Instant; | |
#[tokio::main(flavor = "multi_thread", worker_threads = 1)] | |
async fn main() { | |
let async_fn = reqwest::get("http://robertohuertas.com"); | |
let timed_async_fn = TimedWrapperStacked::new(async_fn); | |
let (resp, time) = timed_async_fn.await; | |
println!( | |
"Got a HTTP {} in {}ms", | |
resp.unwrap().status(), | |
time.as_millis() | |
) | |
} | |
struct TimedWrapperStacked<F: Future> { | |
start: Option<Instant>, | |
inner_fut: F, | |
} | |
impl<F: Future> TimedWrapperStacked<F> { | |
fn new(inner_fut: F) -> Self { | |
Self { | |
start: None, | |
inner_fut, | |
} | |
} | |
fn project(self: Pin<&mut Self>) -> (&mut Option<Instant>, Pin<&mut F>) { | |
unsafe { | |
let this = self.get_unchecked_mut(); | |
(&mut this.start, Pin::new_unchecked(&mut this.inner_fut)) | |
} | |
} | |
} | |
impl<F: Future> Future for TimedWrapperStacked<F> { | |
type Output = (F::Output, Duration); | |
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> { | |
let (start, fut) = self.project(); | |
let start = start.get_or_insert_with(Instant::now); | |
let result = fut.poll(cx); | |
let elapsed = start.elapsed(); | |
match result { | |
task::Poll::Ready(output) => task::Poll::Ready((output, elapsed)), | |
task::Poll::Pending => task::Poll::Pending, | |
} | |
} | |
} | |
#[pin_project] | |
struct TimedWrapperProjected<F: Future> { | |
start: Option<Instant>, | |
#[pin] | |
inner_fut: F, | |
} | |
impl<F: Future> TimedWrapperProjected<F> { | |
fn new(inner_fut: F) -> Self { | |
Self { | |
start: None, | |
inner_fut, | |
} | |
} | |
} | |
impl<F: Future> Future for TimedWrapperProjected<F> { | |
type Output = (F::Output, Duration); | |
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> { | |
let this = self.project(); | |
let start = this.start.get_or_insert_with(Instant::now); | |
let result = this.inner_fut.poll(cx); | |
let elapsed = start.elapsed(); | |
match result { | |
task::Poll::Ready(output) => task::Poll::Ready((output, elapsed)), | |
task::Poll::Pending => task::Poll::Pending, | |
} | |
} | |
} | |
struct TimedWrapperBoxed<F: Future> { | |
start: Option<Instant>, | |
inner_fut: Pin<Box<F>>, | |
} | |
impl<F: Future> TimedWrapperBoxed<F> { | |
fn new(inner_fut: F) -> Self { | |
Self { | |
start: None, | |
inner_fut: Box::pin(inner_fut), | |
} | |
} | |
} | |
impl<F: Future> Future for TimedWrapperBoxed<F> { | |
type Output = (F::Output, Duration); | |
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> { | |
let start = self.start.get_or_insert_with(Instant::now).clone(); | |
let result = self.inner_fut.as_mut().poll(cx); | |
let elapsed = start.elapsed(); | |
match result { | |
task::Poll::Ready(output) => task::Poll::Ready((output, elapsed)), | |
task::Poll::Pending => task::Poll::Pending, | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment