Skip to content

Commit

Permalink
Update async-io to 2 and update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
oxalica committed Oct 23, 2023
1 parent 0927df9 commit 4568bd6
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 23 deletions.
62 changes: 48 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ name = "bench"
harness = false

[dependencies]
async-io = { version = "2", optional = true }
futures = { version = "0.3.28", default-features = false, features = ["async-await", "std"] }
lsp-types = "0.94.1"
pin-project-lite = "0.2.9"
Expand All @@ -78,7 +79,7 @@ tracing = { version = "0.1.37", optional = true }
waitpid-any = { version = "0.2.0", optional = true }

[dev-dependencies]
async-io = "1.13.0"
async-io = "2"
async-process = "1.7.0"
clap = { version = "4", default-features = false, features = ["help"] } # Workaround: https://github.com/bheisler/criterion.rs/issues/702
criterion = { version = "0.5.1", features = ["async_tokio"] }
Expand Down
45 changes: 37 additions & 8 deletions src/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,45 @@
//!
//! # Asynchrous I/O drivers
//!
//! For runtime/drivers with uniform interfaces for sync-async conversion like `async_io::Async`,
//! wrapping `PipeStd{in,out}` inside it just works.
//! ## `async-io`
//!
//! Wrapping `PipeStd{in,out}` inside `async_io::Async<T>` works. This should also work for other
//! drivers with a similar generic asynchronous adapter interface.
//!
//! For `async-io` >= 2, feature `async-io` should be enabled to let `Async<PipeStd{in,out}>`
//! implements `Async{Read,Write}`. `async-io` < 2 does not require it to work.
//! See more details in: <https://github.com/smol-rs/async-io/pull/142>
//!
//! ```
//! # async fn work() -> std::io::Result<()> {
//! use futures::AsyncWriteExt;
//!
//! let mut stdout = async_io::Async::new(async_lsp::stdio::PipeStdout::lock()?)?;
//! stdout.write_all(b"truly async, without spawning blocking task!").await?;
//! // For `async-io` >= 2, this requires `async-io` feature to work.
#![cfg_attr(not(feature = "async-io"), doc = "# #[cfg(never)]")]
//! stdout.write_all(b"never spawns blocking tasks").await?;
//! // This always work.
//! (&stdout).write_all(b"never spawns blocking tasks").await?;
//! # Ok(())
//! # }
//! ```
//!
//! For `tokio` runtime, their interface is
//! [less ergonomic](https://github.com/tokio-rs/tokio/issues/5785).
//! We provide a wrapper method `PipeStdin::lock_tokio` for an `tokio::io::AsyncRead`
//! compatible interface. [`PipeStdout`] works in class. All of them are gated under feature
//! `tokio`.
//! ## `tokio`
//!
//! There are methods `PipeStd{in,out}::{lock,try_into}_tokio` gated under feature `tokio` to
//! work with `tokio` runtime. The returned type implements coresponding
//! `tokio::io::Async{Read,Write}` interface.
//!
//! ```
//! # #[cfg(feature = "tokio")]
//! # async fn work() -> std::io::Result<()> {
//! use tokio::io::AsyncWriteExt;
//!
//! let mut stdout = async_lsp::stdio::PipeStdout::lock_tokio()?;
//! stdout.write_all(b"never spawns blocking tasks").await?;
//! # Ok(())
//! # }
//! ```
use std::io::{self, Error, ErrorKind, IoSlice, Read, Result, StdinLock, StdoutLock, Write};
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};

Expand Down Expand Up @@ -113,6 +134,10 @@ impl AsRawFd for PipeStdin {
}
}

// Invariant: `AsFd::as_fd` never changes through its lifetime.
#[cfg(feature = "async-io")]
unsafe impl async_io::IoSafe for PipeStdin {}

// NB. Bypass the internal buffer of `StdinLock` here to keep this in sync with the readiness of
// the underlying FD (which is relied by the I/O re/actor).
impl Read for &'_ PipeStdin {
Expand Down Expand Up @@ -165,6 +190,10 @@ impl AsRawFd for PipeStdout {
}
}

// Invariant: `AsFd::as_fd` never changes through its lifetime.
#[cfg(feature = "async-io")]
unsafe impl async_io::IoSafe for PipeStdout {}

// NB. See `Read` impl.
impl Write for &'_ PipeStdout {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
Expand Down

0 comments on commit 4568bd6

Please sign in to comment.