salvo: A method to bypass the issue of having pointers in a handling function that cannot be Send.

use std::convert::Infallible;
use std::future::Future;
use std::net::SocketAddr;
use std::pin::Pin;
use std::task::{Context, Poll};

use bytes::Bytes;
use http_body_util::Full;
use hyper::{Request, Response};
use hyper::server::conn::http1;
use hyper::service::service_fn;
use tokio::net::TcpListener;

#[repr(transparent)]
struct AsyncFuture<F>(F);

unsafe impl<F: Future> Send for AsyncFuture<F> {}

impl<F: Future> Future for AsyncFuture<F> {
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        unsafe {
            Pin::new_unchecked(&mut self.get_unchecked_mut().0).poll(cx)
        }
    }
}

fn hello(_: Request<hyper::body::Incoming>) -> AsyncFuture<Pin<Box<dyn Future<Output=Result<Response<Full<Bytes>>, Infallible>>>>> {
    let f = async move {
        let a = 10;
        let p = &a as *const i32;
        tokio::task::yield_now().await;
        println!("{:p}", p);
        Ok::<Response<Full<Bytes>>, Infallible>(Response::new(Full::new(Bytes::from("Hello World!"))))
    };
    AsyncFuture(Box::pin(f))
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    pretty_env_logger::init();
    let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();
    let listener = TcpListener::bind(addr).await?;
    println!("Listening on http://{}", addr);
    loop {
        let (stream, _) = listener.accept().await?;
        tokio::task::spawn(async move {
            if let Err(err) = http1::Builder::new()
                .serve_connection(stream, service_fn(hello))
                .await
            {
                println!("Error serving connection: {:?}", err);
            }
        });
    }
}

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 26 (12 by maintainers)

Most upvoted comments

我想想 是提供一个参数或者feature来处理一下这个比较特殊的情况.