Skip to content

Instantly share code, notes, and snippets.

@robertohuertasm
Created February 6, 2022 22:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robertohuertasm/5c6a868f94b432f158c0793fa795ced2 to your computer and use it in GitHub Desktop.
Save robertohuertasm/5c6a868f94b432f158c0793fa795ced2 to your computer and use it in GitHub Desktop.
Playing with Pin
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