#![deny(warnings)] use hyper::server::conn::Http; use std::cell::Cell; use std::net::SocketAddr; use std::rc::Rc; use tokio::net::TcpListener; use hyper::body::{Bytes, HttpBody}; use hyper::header::{HeaderMap, HeaderValue}; use hyper::service::service_fn; use hyper::{Error, Response}; use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; struct Body { // Our Body type is !Send and !Sync: _marker: PhantomData<*const ()>, data: Option, } impl From for Body { fn from(a: String) -> Self { Body { _marker: PhantomData, data: Some(a.into()), } } } impl HttpBody for Body { type Data = Bytes; type Error = Error; fn poll_data( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll>> { Poll::Ready(self.get_mut().data.take().map(Ok)) } fn poll_trailers( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll>, Self::Error>> { Poll::Ready(Ok(None)) } } fn main() -> Result<(), Box> { pretty_env_logger::init(); // Configure a runtime that runs everything on the current thread let rt = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .expect("build runtime"); // Combine it with a `LocalSet, which means it can spawn !Send futures... let local = tokio::task::LocalSet::new(); local.block_on(&rt, run()) } async fn run() -> Result<(), Box> { let addr: SocketAddr = ([127, 0, 0, 1], 3000).into(); // Using a !Send request counter is fine on 1 thread... let counter = Rc::new(Cell::new(0)); let listener = TcpListener::bind(addr).await?; println!("Listening on http://{}", addr); loop { let (stream, _) = listener.accept().await?; // For each connection, clone the counter to use in our service... let cnt = counter.clone(); let service = service_fn(move |_| { let prev = cnt.get(); cnt.set(prev + 1); let value = cnt.get(); async move { Ok::<_, Error>(Response::new(Body::from(format!("Request #{}", value)))) } }); tokio::task::spawn_local(async move { if let Err(err) = Http::new() .with_executor(LocalExec) .serve_connection(stream, service) .await { println!("Error serving connection: {:?}", err); } }); } } // Since the Server needs to spawn some background tasks, we needed // to configure an Executor that can spawn !Send futures... #[derive(Clone, Copy, Debug)] struct LocalExec; impl hyper::rt::Executor for LocalExec where F: std::future::Future + 'static, // not requiring `Send` { fn execute(&self, fut: F) { // This will spawn into the currently running `LocalSet`. tokio::task::spawn_local(fut); } }