Skip to content

Instantly share code, notes, and snippets.

@LucioFranco
Last active August 18, 2020 14:46
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 LucioFranco/ec8c6617b7193fd062d1ddc32b5bb991 to your computer and use it in GitHub Desktop.
Save LucioFranco/ec8c6617b7193fd062d1ddc32b5bb991 to your computer and use it in GitHub Desktop.
// This example shows how to use the tokio runtime with any other executor
//
// The main components are a spawn fn that will wrap futures in a special future
// that will always enter the tokio context on poll. This only spawns on extra thread
// to manage and run the tokio drivers in the background.
//
// Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=22c3645ba6a03ec77459fd1dfc9f35f1
use tokio::net::TcpListener;
use tokio::sync::oneshot;
fn main() {
let (tx, rx) = oneshot::channel();
my_custom_runtime::spawn(async move {
let listener = TcpListener::bind("0.0.0.0:0").await.unwrap();
println!("addr: {:?}", listener.local_addr());
tx.send(()).unwrap();
});
futures::executor::block_on(rx).unwrap();
}
mod my_custom_runtime {
use once_cell::sync::Lazy;
use pin_project::pin_project;
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use tokio::runtime::Handle;
pub fn spawn(f: impl Future<Output = ()> + Send + 'static) {
EXECUTOR.spawn(f);
}
struct ThreadPool {
inner: futures::executor::ThreadPool,
rt: tokio::runtime::Runtime,
}
static EXECUTOR: Lazy<ThreadPool> = Lazy::new(|| {
// Spawn tokio runtime on a single background thread
// enabling IO and timers.
let rt = tokio::runtime::Builder::new()
.basic_scheduler()
.enable_all()
.core_threads(1)
.build()
.unwrap();
let inner = futures::executor::ThreadPool::builder().create().unwrap();
ThreadPool { inner, rt }
});
impl ThreadPool {
fn spawn(&self, f: impl Future<Output = ()> + Send + 'static) {
let handle = self.rt.handle().clone();
self.inner.spawn_ok(TokioIo { handle, inner: f });
}
}
#[pin_project]
struct TokioIo<F> {
#[pin]
inner: F,
handle: Handle,
}
impl<F: Future> Future for TokioIo<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let me = self.project();
// Compiler is having trouble figuring out these
// lifetimes.
let handle = me.handle;
let fut = me.inner;
handle.enter(|| fut.poll(cx))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment