Fix compilation errors

This commit is contained in:
Stjepan Glavina 2020-08-26 23:59:49 +02:00
parent a2a2601fc4
commit 1a542a8864
25 changed files with 132 additions and 276 deletions

View File

@ -12,58 +12,47 @@ keywords = ["async", "await", "future", "io", "networking"]
categories = ["asynchronous", "concurrency", "network-programming"]
readme = "README.md"
[features]
default = []
tokio02 = ["tokio"] # Optional feature for compatibility with tokio-based libraries.
[dependencies]
async-channel = "1.1.1"
async-executor = "0.1.1"
async-io = "0.1.5"
blocking = "0.5.0"
cfg-if = "0.1.10"
easy-parallel = "3.1.0"
futures-lite = "0.1.9"
num_cpus = "1.13.0"
[dependencies.tokio]
version = "0.2.22"
default-features = false
features = ["rt-threaded"]
optional = true
async-channel = "1.4.1"
async-executor = "0.2.0"
async-fs = "1.1.1"
async-io = "0.2.1"
async-lock = "2.0.1"
async-net = "1.0.0"
async-process = "0.1.3"
blocking = "0.6.0"
futures-lite = "1.0.0"
once_cell = "1.4.1"
[dev-dependencies]
anyhow = "1.0.31"
async-channel = "1.1.1"
anyhow = "1.0.32"
async-channel = "1.4.1"
async-dup = "1.2.1"
async-h1 = "2.1.0"
async-h1 = "2.1.2"
async-native-tls = "0.3.3"
async-net = "0.1.1"
async-std = "1.6.2"
async-tungstenite = { version = "0.7.1", features = ["async-native-tls"] }
async-std = "1.6.3"
async-tungstenite = { version = "0.8.0", features = ["async-native-tls"] }
base64 = "0.12.3"
ctrlc = "3.1.5"
ctrlc = "3.1.6"
doc-comment = "0.3"
futures = "0.3.5"
http = "0.2.1"
http-types = "2.3.0"
http-types = "2.4.0"
hyper = { version = "0.13.7", default-features = false, features = ["stream"] }
native-tls = "0.2.4"
num_cpus = "1.13.0"
reqwest = "0.10.6"
scraper = "0.12.0"
signal-hook = "0.1.16"
smol = { path = ".", features = ["tokio02"] }
surf = { version = "2.0.0-alpha.4", default-features = false, features = ["h1-client"] }
tempfile = "3.1.0"
tide = "0.12.0"
tungstenite = "0.11.0"
tide = "0.13.0"
tokio = { version = "0.2.22", default-features = false, features = ["rt-threaded"] }
tungstenite = "0.11.1"
url = "2.1.1"
warp = "0.2.4"
[target.'cfg(target_os = "linux")'.dev-dependencies]
inotify = { version = "0.8.3", default-features = false }
nix = "0.17.0"
nix = "0.18.0"
timerfd = "1.1.1"
[target.'cfg(windows)'.dev-dependencies]

View File

@ -25,7 +25,8 @@ async fn fetch(req: Request) -> Result<Response> {
// Connect to the host.
let socket_addr = {
let host = host.clone();
smol::unblock!((host.as_str(), port).to_socket_addrs())?
smol::unblock(move || (host.as_str(), port).to_socket_addrs())
.await?
.next()
.context("cannot resolve address")?
};
@ -45,7 +46,7 @@ async fn fetch(req: Request) -> Result<Response> {
}
fn main() -> Result<()> {
smol::run(async {
smol::block_on(async {
// Create a request.
let addr = "https://www.rust-lang.org";
let req = Request::new(Method::Get, Url::parse(addr)?);

View File

@ -18,7 +18,7 @@ use std::net::TcpListener;
use anyhow::Result;
use async_native_tls::{Identity, TlsAcceptor};
use http_types::{Request, Response, StatusCode};
use smol::{future, Async, Task};
use smol::{future, Async};
/// Serves a request and returns a response.
async fn serve(req: Request) -> http_types::Result<Response> {
@ -47,7 +47,7 @@ async fn listen(listener: Async<TcpListener>, tls: Option<TlsAcceptor>) -> Resul
let task = match &tls {
None => {
let stream = async_dup::Arc::new(stream);
Task::spawn(async move {
smol::spawn(async move {
if let Err(err) = async_h1::accept(stream, serve).await {
println!("Connection error: {:#?}", err);
}
@ -58,7 +58,7 @@ async fn listen(listener: Async<TcpListener>, tls: Option<TlsAcceptor>) -> Resul
match tls.accept(stream).await {
Ok(stream) => {
let stream = async_dup::Arc::new(async_dup::Mutex::new(stream));
Task::spawn(async move {
smol::spawn(async move {
if let Err(err) = async_h1::accept(stream, serve).await {
println!("Connection error: {:#?}", err);
}
@ -83,13 +83,13 @@ fn main() -> Result<()> {
let tls = TlsAcceptor::from(native_tls::TlsAcceptor::new(identity)?);
// Start HTTP and HTTPS servers.
smol::run(async {
smol::block_on(async {
let http = listen(Async::<TcpListener>::bind(([127, 0, 0, 1], 8000))?, None);
let https = listen(
Async::<TcpListener>::bind(([127, 0, 0, 1], 8001))?,
Some(tls),
);
future::try_join(http, https).await?;
future::try_zip(http, https).await?;
Ok(())
})
}

View File

@ -17,7 +17,7 @@ use std::net::TcpStream;
use smol::{future, io, Async, Unblock};
fn main() -> io::Result<()> {
smol::run(async {
smol::block_on(async {
// Connect to the server and create async stdin and stdout.
let stream = Async::<TcpStream>::connect(([127, 0, 0, 1], 6000)).await?;
let stdin = Unblock::new(std::io::stdin());

View File

@ -17,7 +17,7 @@ use std::net::{SocketAddr, TcpListener, TcpStream};
use async_channel::{bounded, Receiver, Sender};
use async_dup::Arc;
use smol::{io, prelude::*, Async, Task};
use smol::{io, prelude::*, Async};
/// An event on the chat server.
enum Event {
@ -76,7 +76,7 @@ async fn read_messages(sender: Sender<Event>, client: Arc<Async<TcpStream>>) ->
}
fn main() -> io::Result<()> {
smol::run(async {
smol::block_on(async {
// Create a listener for incoming client connections.
let listener = Async::<TcpListener>::bind(([127, 0, 0, 1], 6000))?;
@ -86,7 +86,7 @@ fn main() -> io::Result<()> {
// Spawn a background task that dispatches events to clients.
let (sender, receiver) = bounded(100);
Task::spawn(dispatch(receiver)).detach();
smol::spawn(dispatch(receiver)).detach();
loop {
// Accept the next connection.
@ -95,7 +95,7 @@ fn main() -> io::Result<()> {
let sender = sender.clone();
// Spawn a background task reading messages from the client.
Task::spawn(async move {
smol::spawn(async move {
// Client starts with a `Join` event.
let _ = sender.send(Event::Join(addr, client.clone())).await;

View File

@ -6,8 +6,6 @@
//! cargo run --example ctrl-c
//! ```
use smol::future;
fn main() {
// Set a handler that sends a message through a channel.
let (s, ctrl_c) = async_channel::bounded(100);
@ -16,7 +14,7 @@ fn main() {
};
ctrlc::set_handler(handle).unwrap();
smol::run(async {
smol::block_on(async {
println!("Waiting for Ctrl-C...");
// Receive a message that indicates the Ctrl-C signal occurred.

View File

@ -10,9 +10,9 @@ use smol::{io, prelude::*, Async, Unblock};
use std::net::{TcpStream, ToSocketAddrs};
fn main() -> io::Result<()> {
smol::run(async {
smol::block_on(async {
// Connect to http://example.com
let mut addrs = smol::unblock!(("example.com", 80).to_socket_addrs())?;
let mut addrs = smol::unblock(move || ("example.com", 80).to_socket_addrs()).await?;
let addr = addrs.next().unwrap();
let mut stream = Async::<TcpStream>::connect(addr).await?;

View File

@ -15,7 +15,7 @@ use anyhow::{bail, Context as _, Error, Result};
use async_native_tls::TlsStream;
use http::Uri;
use hyper::{Body, Client, Request, Response};
use smol::{io, prelude::*, Async, Task};
use smol::{io, prelude::*, Async};
/// Sends a request and fetches the response.
async fn fetch(req: Request<Body>) -> Result<Response<Body>> {
@ -27,7 +27,7 @@ async fn fetch(req: Request<Body>) -> Result<Response<Body>> {
}
fn main() -> Result<()> {
smol::run(async {
smol::block_on(async {
// Create a request.
let req = Request::get("https://www.rust-lang.org").body(Body::empty())?;
@ -55,7 +55,7 @@ struct SmolExecutor;
impl<F: Future + Send + 'static> hyper::rt::Executor<F> for SmolExecutor {
fn execute(&self, fut: F) {
Task::spawn(async { drop(fut.await) }).detach();
smol::spawn(async { drop(fut.await) }).detach();
}
}
@ -81,7 +81,8 @@ impl hyper::service::Service<Uri> for SmolConnector {
let socket_addr = {
let host = host.to_string();
let port = uri.port_u16().unwrap_or(80);
smol::unblock!((host.as_str(), port).to_socket_addrs())?
smol::unblock(move || (host.as_str(), port).to_socket_addrs())
.await?
.next()
.context("cannot resolve address")?
};
@ -93,7 +94,8 @@ impl hyper::service::Service<Uri> for SmolConnector {
let socket_addr = {
let host = host.to_string();
let port = uri.port_u16().unwrap_or(443);
smol::unblock!((host.as_str(), port).to_socket_addrs())?
smol::unblock(move || (host.as_str(), port).to_socket_addrs())
.await?
.next()
.context("cannot resolve address")?
};

View File

@ -21,7 +21,7 @@ use anyhow::{Error, Result};
use async_native_tls::{Identity, TlsAcceptor, TlsStream};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use smol::{future, io, prelude::*, Async, Task};
use smol::{future, io, prelude::*, Async};
/// Serves a request and returns a response.
async fn serve(req: Request<Body>, host: String) -> Result<Response<Body>> {
@ -56,13 +56,13 @@ fn main() -> Result<()> {
let tls = TlsAcceptor::from(native_tls::TlsAcceptor::new(identity)?);
// Start HTTP and HTTPS servers.
smol::run(async {
smol::block_on(async {
let http = listen(Async::<TcpListener>::bind(([127, 0, 0, 1], 8000))?, None);
let https = listen(
Async::<TcpListener>::bind(([127, 0, 0, 1], 8001))?,
Some(tls),
);
future::try_join(http, https).await?;
future::try_zip(http, https).await?;
Ok(())
})
}
@ -73,7 +73,7 @@ struct SmolExecutor;
impl<F: Future + Send + 'static> hyper::rt::Executor<F> for SmolExecutor {
fn execute(&self, fut: F) {
Task::spawn(async { drop(fut.await) }).detach();
smol::spawn(async { drop(fut.await) }).detach();
}
}

View File

@ -32,7 +32,7 @@ fn main() -> std::io::Result<()> {
}
}
smol::run(async {
smol::block_on(async {
// Watch events in the current directory.
let mut inotify = Async::new(Inotify::init()?)?;
inotify.get_mut().add_watch(".", WatchMask::ALL_EVENTS)?;

View File

@ -35,7 +35,7 @@ fn main() -> std::io::Result<()> {
Ok(())
}
smol::run(async {
smol::block_on(async {
let start = Instant::now();
println!("Sleeping...");

View File

@ -1,48 +0,0 @@
//! Demonstrates how to use `async-std`, `tokio`, `surf`, and `request`.
//!
//! For compatibility with tokio-based libraries, enable the `tokio02` feature flag:
//!
//! ```toml
//! [dependencies]
//! smol = { version = "0.3", features = ["tokio02"] }
//! ```
//!
//! Run with:
//!
//! ```
//! cargo run --example other-runtimes
//! ```
use std::time::{Duration, Instant};
use anyhow::{Error, Result};
fn main() -> Result<()> {
smol::run(async {
// Sleep using async-std.
let start = Instant::now();
println!("Sleeping using async-std...");
async_std::task::sleep(Duration::from_secs(1)).await;
println!("Woke up after {:?}", start.elapsed());
// Sleep using tokio (the `tokio02` feature must be enabled).
let start = Instant::now();
println!("Sleeping using tokio...");
tokio::time::delay_for(Duration::from_secs(1)).await;
println!("Woke up after {:?}", start.elapsed());
// Make a GET request using surf.
let body = surf::get("https://www.rust-lang.org")
.recv_string()
.await
.map_err(Error::msg)?;
println!("Body from surf: {:?}", body);
// Make a GET request using reqwest (the `tokio02` feature must be enabled).
let resp = reqwest::get("https://www.rust-lang.org").await?;
let body = resp.text().await?;
println!("Body from reqwest: {:?}", body);
Ok(())
})
}

View File

@ -33,7 +33,8 @@ async fn fetch(addr: &str) -> Result<Vec<u8>> {
// Connect to the host.
let socket_addr = {
let host = host.clone();
smol::unblock!((host.as_str(), port).to_socket_addrs())?
smol::unblock(move || (host.as_str(), port).to_socket_addrs())
.await?
.next()
.context("cannot resolve address")?
};
@ -59,7 +60,7 @@ async fn fetch(addr: &str) -> Result<Vec<u8>> {
}
fn main() -> Result<()> {
smol::run(async {
smol::block_on(async {
let addr = "https://www.rust-lang.org";
let resp = fetch(addr).await?;
println!("{}", String::from_utf8_lossy(&resp));

View File

@ -17,7 +17,7 @@ use std::net::{TcpListener, TcpStream};
use anyhow::Result;
use async_native_tls::{Identity, TlsAcceptor};
use smol::{future, prelude::*, Async, Task};
use smol::{future, prelude::*, Async};
const RESPONSE: &[u8] = br#"
HTTP/1.1 200 OK
@ -65,7 +65,7 @@ async fn listen(listener: Async<TcpListener>, tls: Option<TlsAcceptor>) -> Resul
let tls = tls.clone();
// Spawn a background task serving this connection.
Task::spawn(async move {
smol::spawn(async move {
if let Err(err) = serve(stream, tls).await {
println!("Connection error: {:#?}", err);
}
@ -80,13 +80,13 @@ fn main() -> Result<()> {
let tls = TlsAcceptor::from(native_tls::TlsAcceptor::new(identity)?);
// Start HTTP and HTTPS servers.
smol::run(async {
smol::block_on(async {
let http = listen(Async::<TcpListener>::bind(([127, 0, 0, 1], 8000))?, None);
let https = listen(
Async::<TcpListener>::bind(([127, 0, 0, 1], 8001))?,
Some(tls),
);
future::try_join(http, https).await?;
future::try_zip(http, https).await?;
Ok(())
})
}

View File

@ -17,7 +17,7 @@ use std::net::TcpStream;
use smol::{future, io, Async, Unblock};
fn main() -> io::Result<()> {
smol::run(async {
smol::block_on(async {
// Create async stdin and stdout handles.
let stdin = Unblock::new(std::io::stdin());
let mut stdout = Unblock::new(std::io::stdout());
@ -28,7 +28,7 @@ fn main() -> io::Result<()> {
println!("Type a message and hit enter!\n");
// Pipe messages from stdin to the server and pipe messages from the server to stdout.
future::try_join(
future::try_zip(
io::copy(stdin, &mut &stream),
io::copy(&stream, &mut stdout),
)

View File

@ -14,7 +14,7 @@
use std::net::{TcpListener, TcpStream};
use smol::{io, Async, Task};
use smol::{io, Async};
/// Echoes messages from the client back to it.
async fn echo(stream: Async<TcpStream>) -> io::Result<()> {
@ -23,7 +23,7 @@ async fn echo(stream: Async<TcpStream>) -> io::Result<()> {
}
fn main() -> io::Result<()> {
smol::run(async {
smol::block_on(async {
// Create a listener.
let listener = Async::<TcpListener>::bind(([127, 0, 0, 1], 7000))?;
println!("Listening on {}", listener.get_ref().local_addr()?);
@ -35,7 +35,7 @@ fn main() -> io::Result<()> {
println!("Accepted client: {}", peer_addr);
// Spawn a task that echoes messages from the client back to it.
Task::spawn(echo(stream)).detach();
smol::spawn(echo(stream)).detach();
}
})
}

View File

@ -24,7 +24,7 @@ fn main() -> Result<()> {
builder.add_root_certificate(Certificate::from_pem(include_bytes!("certificate.pem"))?);
let tls = TlsConnector::from(builder);
smol::run(async {
smol::block_on(async {
// Create async stdin and stdout handles.
let stdin = Unblock::new(std::io::stdin());
let mut stdout = Unblock::new(std::io::stdout());
@ -37,7 +37,7 @@ fn main() -> Result<()> {
// Pipe messages from stdin to the server and pipe messages from the server to stdout.
let stream = async_dup::Mutex::new(stream);
future::try_join(
future::try_zip(
io::copy(stdin, &mut &stream),
io::copy(&stream, &mut stdout),
)

View File

@ -16,7 +16,7 @@ use std::net::{TcpListener, TcpStream};
use anyhow::Result;
use async_native_tls::{Identity, TlsAcceptor, TlsStream};
use smol::{io, Async, Task};
use smol::{io, Async};
/// Echoes messages from the client back to it.
async fn echo(stream: TlsStream<Async<TcpStream>>) -> Result<()> {
@ -30,7 +30,7 @@ fn main() -> Result<()> {
let identity = Identity::from_pkcs12(include_bytes!("identity.pfx"), "password")?;
let tls = TlsAcceptor::from(native_tls::TlsAcceptor::new(identity)?);
smol::run(async {
smol::block_on(async {
// Create a listener.
let listener = Async::<TcpListener>::bind(([127, 0, 0, 1], 7001))?;
println!("Listening on {}", listener.get_ref().local_addr()?);
@ -46,7 +46,7 @@ fn main() -> Result<()> {
);
// Spawn a task that echoes messages from the client back to it.
Task::spawn(echo(stream)).detach();
smol::spawn(echo(stream)).detach();
}
})
}

View File

@ -12,7 +12,7 @@ fn main() -> std::io::Result<()> {
use smol::{prelude::*, Async};
smol::run(async {
smol::block_on(async {
// Create a Unix stream that receives a byte on each signal occurrence.
let (a, mut b) = Async::<UnixStream>::pair()?;
signal_hook::pipe::register(signal_hook::SIGINT, a)?;

View File

@ -11,7 +11,6 @@ use std::collections::{HashSet, VecDeque};
use anyhow::Result;
use async_channel::{bounded, Sender};
use scraper::{Html, Selector};
use smol::Task;
const ROOT: &str = "https://www.rust-lang.org";
@ -34,7 +33,7 @@ fn links(body: String) -> Vec<String> {
}
fn main() -> Result<()> {
smol::run(async {
smol::block_on(async {
let mut seen = HashSet::new();
let mut queue = VecDeque::new();
seen.insert(ROOT.to_string());
@ -53,7 +52,7 @@ fn main() -> Result<()> {
Some(url) => {
println!("{}", url);
tasks += 1;
Task::spawn(fetch(url, s.clone())).detach();
smol::spawn(fetch(url, s.clone())).detach();
}
}
}

View File

@ -35,7 +35,8 @@ async fn connect(addr: &str, tls: TlsConnector) -> Result<(WsStream, Response)>
// Resolve the address.
let socket_addr = {
let host = host.clone();
smol::unblock!((host.as_str(), port).to_socket_addrs())?
smol::unblock(move || (host.as_str(), port).to_socket_addrs())
.await?
.next()
.context("cannot resolve address")?
};
@ -64,7 +65,7 @@ fn main() -> Result<()> {
builder.add_root_certificate(Certificate::from_pem(include_bytes!("certificate.pem"))?);
let tls = TlsConnector::from(builder);
smol::run(async {
smol::block_on(async {
// Connect to the server.
let (mut stream, resp) = connect("wss://127.0.0.1:9001", tls).await?;
dbg!(resp);

View File

@ -20,7 +20,7 @@ use anyhow::{Context as _, Result};
use async_native_tls::{Identity, TlsAcceptor, TlsStream};
use async_tungstenite::WebSocketStream;
use futures::sink::{Sink, SinkExt};
use smol::{future, prelude::*, Async, Task};
use smol::{future, prelude::*, Async};
use tungstenite::Message;
/// Echoes messages from the client back to it.
@ -46,13 +46,13 @@ async fn listen(listener: Async<TcpListener>, tls: Option<TlsAcceptor>) -> Resul
match &tls {
None => {
let stream = WsStream::Plain(async_tungstenite::accept_async(stream).await?);
Task::spawn(echo(stream)).detach();
smol::spawn(echo(stream)).detach();
}
Some(tls) => {
// In case of WSS, establish a secure TLS connection first.
let stream = tls.accept(stream).await?;
let stream = WsStream::Tls(async_tungstenite::accept_async(stream).await?);
Task::spawn(echo(stream)).detach();
smol::spawn(echo(stream)).detach();
}
}
}
@ -64,13 +64,13 @@ fn main() -> Result<()> {
let tls = TlsAcceptor::from(native_tls::TlsAcceptor::new(identity)?);
// Start WS and WSS servers.
smol::run(async {
smol::block_on(async {
let ws = listen(Async::<TcpListener>::bind(([127, 0, 0, 1], 9000))?, None);
let wss = listen(
Async::<TcpListener>::bind(([127, 0, 0, 1], 9001))?,
Some(tls),
);
future::try_join(ws, wss).await?;
future::try_zip(ws, wss).await?;
Ok(())
})
}

View File

@ -10,7 +10,7 @@
fn main() -> std::io::Result<()> {
use std::path::PathBuf;
use smol::{io, prelude::*, Async, Task, Unblock};
use smol::{io, prelude::*, Async, Unblock};
use tempfile::tempdir;
use uds_windows::{UnixListener, UnixStream};
@ -28,13 +28,13 @@ fn main() -> std::io::Result<()> {
let dir = tempdir()?;
let path = dir.path().join("socket");
smol::run(async {
smol::block_on(async {
// Create a listener.
let listener = Async::new(UnixListener::bind(&path)?)?;
println!("Listening on {:?}", listener.get_ref().local_addr()?);
// Spawn a client task.
let task = Task::spawn(client(path));
let task = smol::spawn(client(path));
// Accept the client.
let (stream, _) = listener.read_with(|l| l.accept()).await?;

1
rustfmt.toml Normal file
View File

@ -0,0 +1 @@
version = 'Two'

View File

@ -5,12 +5,11 @@
//! Connect to an HTTP website, make a GET request, and pipe the response to the standard output:
//!
//! ```
//! use async_net::TcpStream;
//! use smol::{io, prelude::*, Unblock};
//! use smol::{io, net, prelude::*, Unblock};
//!
//! fn main() -> io::Result<()> {
//! smol::run(async {
//! let mut stream = TcpStream::connect("example.com:80").await?;
//! smol::block_on(async {
//! let mut stream = net::TcpStream::connect("example.com:80").await?;
//! let req = b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
//! stream.write_all(req).await?;
//!
@ -21,32 +20,14 @@
//! }
//! ```
//!
//! This example uses [`async-net`] for networking, but you can also use the primitive [`Async`]
//! type. See the [full code][get-request].
//! This example uses the [`net`] module for networking, but you can also use the primitive
//! [`Async`] type. See the [full code][get-request].
//!
//! Look inside the [examples] directory for more.
//!
//! [`async-net`]: https://docs.rs/async-net
//! [examples]: https://github.com/stjepang/smol/tree/master/examples
//! [get-request]: https://github.com/stjepang/smol/blob/master/examples/get-request.rs
//!
//! # Compatibility
//!
//! All async libraries work with smol out of the box.
//!
//! The only exception is [tokio], which is traditionally incompatible with [futures] and crashes
//! when called from other executors. Fortunately, there are ways around it.
//!
//! Enable the `tokio02` feature flag and [`smol::run()`][`crate::run()`] will create a minimal
//! tokio runtime for its libraries:
//!
//! ```toml
//! [dependencies]
//! smol = { version = "0.3", features = ["tokio02"] }
//! ```
//!
//! [tokio]: https://docs.rs/tokio
//! [futures]: https://docs.rs/futures
#![forbid(unsafe_code)]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
@ -54,31 +35,38 @@
#[cfg(doctest)]
doc_comment::doctest!("../README.md");
use std::env;
use std::future::Future;
use std::panic::catch_unwind;
use std::thread;
use async_executor::{Executor, LocalExecutor};
use cfg_if::cfg_if;
use easy_parallel::Parallel;
use once_cell::sync::Lazy;
#[doc(inline)]
pub use {
async_executor::Task,
async_io::Async,
async_io::Timer,
async_executor::{Executor, LocalExecutor, Task},
async_io::{block_on, Async, Timer},
blocking::{unblock, Unblock},
futures_lite::{future, io, stream},
futures_lite::{pin, ready},
};
/// Async traits and their extensions.
///
/// # Examples
///
/// ```
/// use smol::prelude::*;
/// ```
// TODO: Mutex::lock_arc() -> ArcMutexGuard, also Mutex::try_lock_arc()
#[doc(inline)]
pub use {
async_channel as channel, async_fs as fs, async_lock as lock, async_net as net,
async_process as process,
};
pub mod prelude {
//! Traits [`Future`], [`AsyncBufRead`], [`AsyncRead`], [`AsyncSeek`], [`AsyncWrite`], and
//! their extensions.
//!
//! # Examples
//!
//! ```
//! use smol::prelude::*;
//! ```
#[doc(no_inline)]
pub use futures_lite::{
future::{Future, FutureExt},
@ -90,111 +78,35 @@ pub mod prelude {
};
}
/// Starts a thread-local executor and then runs the future.
/// Spawns a task onto the single-threaded global executor.
///
/// There is a single-threaded global executor that gets lazily initialized on first use. It is
/// advisable to use it in tests or small programs, but it is otherwise a better idea to define
/// your own [`Executor`]s.
///
/// # Examples
///
/// ```
/// use smol::Task;
/// let task = smol::spawn(async {
/// 1 + 2
/// });
///
/// smol::block_on(async {
/// let task = Task::local(async {
/// println!("Hello world");
/// });
/// task.await;
/// })
/// assert_eq!(task.await, 3);
/// });
/// ```
pub fn block_on<T>(future: impl Future<Output = T>) -> T {
let local_ex = LocalExecutor::new();
cfg_if! {
if #[cfg(not(feature = "tokio02"))] {
local_ex.run(future)
} else {
// A minimal tokio runtime to support libraries depending on it.
let mut rt = tokio::runtime::Builder::new()
.enable_all()
.basic_scheduler()
.build()
.expect("cannot start tokio runtime");
let handle = rt.handle().clone();
// A channel that coordinates shutdown when the main future completes.
let (trigger, shutdown) = async_channel::unbounded::<()>();
let future = async move {
let _trigger = trigger; // Dropped at the end of this async block.
future.await
};
Parallel::new()
.add(|| rt.block_on(shutdown.recv()))
.finish(|| handle.enter(|| local_ex.run(future)))
.1
}
}
}
/// Starts a thread-local and a multi-threaded executor and then runs the future.
///
/// This function runs two executors at the same time:
///
/// 1. The current thread runs a [`LocalExecutor`] and the main `future` on it.
/// 2. A thread pool runs an [`Executor`] until the main `future` completes.
///
/// The number of spawned threads matches the number of logical CPU cores on the system, but it can
/// be overriden by setting the `SMOL_THREADS` environment variable.
///
/// # Examples
///
/// ```
/// use smol::Task;
///
/// smol::run(async {
/// let task = Task::spawn(async {
/// println!("Hello world");
/// });
/// task.await;
/// })
/// ```
pub fn run<T>(future: impl Future<Output = T>) -> T {
// A channel that coordinates shutdown when the main future completes.
let (trigger, shutdown) = async_channel::unbounded::<()>();
let future = async move {
let _trigger = trigger; // Dropped at the end of this async block.
future.await
};
let num_threads = {
// Parse SMOL_THREADS or use the number of CPU cores on the system.
env::var("SMOL_THREADS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or_else(|| num_cpus::get())
};
let ex = Executor::new();
let local_ex = LocalExecutor::new();
cfg_if! {
if #[cfg(not(feature = "tokio02"))] {
Parallel::new()
.each(0..num_threads, |_| ex.run(shutdown.recv()))
.finish(|| ex.enter(|| local_ex.run(future)))
.1
} else {
// A minimal tokio runtime to support libraries depending on it.
let mut rt = tokio::runtime::Builder::new()
.enable_all()
.basic_scheduler()
.build()
.expect("cannot start tokio runtime");
let handle = rt.handle().clone();
Parallel::new()
.add(|| ex.enter(|| rt.block_on(shutdown.recv())))
.each(0..num_threads, |_| handle.enter(|| ex.run(shutdown.recv())))
.finish(|| handle.enter(|| ex.enter(|| local_ex.run(future))))
.1
}
}
pub fn spawn<T: Send + 'static>(future: impl Future<Output = T> + Send + 'static) -> Task<T> {
static GLOBAL: Lazy<Executor> = Lazy::new(|| {
thread::Builder::new()
.name("smol".to_string())
.spawn(|| {
loop {
let _ =
catch_unwind(|| async_io::block_on(GLOBAL.run(future::pending::<()>())));
}
})
.unwrap();
Executor::new()
});
GLOBAL.spawn(future)
}