Skip to content

Commit

Permalink
Reenable cap-async-std. (#370)
Browse files Browse the repository at this point in the history
* Reenable cap-async-std.

async-std 1.13.0 is now released with the "io_safety" feature, which
means we can now reenable cap-async-std.

* Update to io-extras 0.18.3.
  • Loading branch information
sunfishcode authored Oct 30, 2024
1 parent ef0c8ac commit f38cbd7
Show file tree
Hide file tree
Showing 18 changed files with 329 additions and 111 deletions.
34 changes: 17 additions & 17 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ exclude = ["/.*"]
rust-version = "1.63"

[dev-dependencies]
#async-std = { version = "1.10.0", features = ["attributes"] }
async-std = { version = "1.13.0", features = ["attributes", "io_safety"] }
anyhow = "1.0.37"
#cap-async-std = { path = "cap-async-std", version = "^0.25.0" }
cap-fs-ext = { path = "cap-fs-ext", version = "^3.3.0" }
cap-net-ext = { path = "cap-net-ext", version = "^3.3.0" }
cap-directories = { path = "cap-directories", version = "^3.3.0" }
cap-std = { path = "cap-std", version = "^3.3.0" }
cap-tempfile = { path = "cap-tempfile", version = "^3.3.0" }
cap-rand = { path = "cap-rand", version = "^3.3.0" }
cap-async-std = { path = "cap-async-std", version = "3.3.0" }
cap-fs-ext = { path = "cap-fs-ext", version = "3.3.0" }
cap-net-ext = { path = "cap-net-ext", version = "3.3.0" }
cap-directories = { path = "cap-directories", version = "3.3.0" }
cap-std = { path = "cap-std", version = "3.3.0" }
cap-tempfile = { path = "cap-tempfile", version = "3.3.0" }
cap-rand = { path = "cap-rand", version = "3.3.0" }
rand = "0.8.1"
tempfile = "3.1.0"
camino = "1.0.5"
Expand Down Expand Up @@ -55,23 +55,23 @@ fs_utf8 = [
"cap-fs-ext/fs_utf8",
"cap-tempfile/fs_utf8",
]
#async_std_fs_utf8 = [
# "cap-async-std/fs_utf8",
# "cap-fs-ext/async_std_fs_utf8"
#]
async_std_fs_utf8 = [
"cap-async-std/fs_utf8",
"cap-fs-ext/async_std_fs_utf8"
]
arf_strings = [
"cap-std/arf_strings",
"cap-fs-ext/arf_strings",
"cap-tempfile/arf_strings",
]
#async_std_arf_strings = [
# "cap-async-std/arf_strings",
# "cap-fs-ext/async_std_arf_strings"
#]
async_std_arf_strings = [
"cap-async-std/arf_strings",
"cap-fs-ext/async_std_arf_strings"
]

[workspace]
members = [
#"cap-async-std",
"cap-async-std",
"cap-fs-ext",
"cap-net-ext",
"cap-directories",
Expand Down
10 changes: 4 additions & 6 deletions cap-async-std/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cap-async-std"
version = "0.25.2"
version = "3.3.0"
description = "Capability-based version of async-std"
authors = [
"Dan Gohman <dev@sunfishcode.online>",
Expand All @@ -11,15 +11,13 @@ keywords = ["network", "file", "async", "future", "await"]
categories = ["filesystem", "network-programming", "asynchronous", "concurrency"]
repository = "https://github.com/bytecodealliance/cap-std"
edition = "2021"
publish = false # temporary, until async-rs/async-std#1036 is available

[dependencies]
arf-strings = { version = "0.7.0", optional = true }
# Enable "unstable" for `spawn_blocking`.
async-std = { version = "1.10.0", features = ["attributes", "unstable"] }
cap-primitives = { path = "../cap-primitives", version = "^0.25.0" }
async-std = { version = "1.13.0", features = ["attributes", "io_safety"] }
cap-primitives = { path = "../cap-primitives", version = "^3.3.0" }
io-lifetimes = { version = "2.0.0", default-features = false, features = ["async-std"] }
io-extras = { version = "0.17.0", features = ["use_async_std"] }
io-extras = { version = "0.18.3", features = ["use_async_std"] }
camino = { version = "1.0.5", optional = true }

[target.'cfg(not(windows))'.dependencies]
Expand Down
84 changes: 84 additions & 0 deletions cap-async-std/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::env::var;
use std::io::Write;

fn main() {
use_feature_or_nothing("windows_file_type_ext");

// Cfgs that users may set.
println!("cargo:rustc-check-cfg=cfg(io_lifetimes_use_std)");

// Don't rerun this on changes other than build.rs, as we only depend on
// the rustc version.
println!("cargo:rerun-if-changed=build.rs");
}

fn use_feature_or_nothing(feature: &str) {
if has_feature(feature) {
use_feature(feature);
}
println!("cargo:rustc-check-cfg=cfg({})", feature);
}

fn use_feature(feature: &str) {
println!("cargo:rustc-cfg={}", feature);
}

/// Test whether the rustc at `var("RUSTC")` supports the given feature.
fn has_feature(feature: &str) -> bool {
can_compile(&format!(
"#![allow(stable_features)]\n#![feature({})]",
feature
))
}

/// Test whether the rustc at `var("RUSTC")` can compile the given code.
fn can_compile<T: AsRef<str>>(test: T) -> bool {
use std::process::Stdio;

let out_dir = var("OUT_DIR").unwrap();
let rustc = var("RUSTC").unwrap();
let target = var("TARGET").unwrap();

// Use `RUSTC_WRAPPER` if it's set, unless it's set to an empty string,
// as documented [here].
// [here]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-reads
let wrapper = var("RUSTC_WRAPPER")
.ok()
.and_then(|w| if w.is_empty() { None } else { Some(w) });

let mut cmd = if let Some(wrapper) = wrapper {
let mut cmd = std::process::Command::new(wrapper);
// The wrapper's first argument is supposed to be the path to rustc.
cmd.arg(rustc);
cmd
} else {
std::process::Command::new(rustc)
};

cmd.arg("--crate-type=rlib") // Don't require `main`.
.arg("--emit=metadata") // Do as little as possible but still parse.
.arg("--target")
.arg(target)
.arg("--out-dir")
.arg(out_dir); // Put the output somewhere inconsequential.

// If Cargo wants to set RUSTFLAGS, use that.
if let Ok(rustflags) = var("CARGO_ENCODED_RUSTFLAGS") {
if !rustflags.is_empty() {
for arg in rustflags.split('\x1f') {
cmd.arg(arg);
}
}
}

let mut child = cmd
.arg("-") // Read from stdin.
.stdin(Stdio::piped()) // Stdin is a pipe.
.stderr(Stdio::null()) // Errors from feature detection aren't interesting and can be confusing.
.spawn()
.unwrap();

writeln!(child.stdin.take().unwrap(), "{}", test.as_ref()).unwrap();

child.wait().unwrap().success()
}
23 changes: 15 additions & 8 deletions cap-async-std/src/fs/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ use cap_primitives::fs::{
remove_open_dir_all, rename, set_permissions, stat, DirOptions, FollowSymlinks, Permissions,
};
use cap_primitives::AmbientAuthority;
use io_lifetimes::raw::{AsRawFilelike, FromRawFilelike};
#[cfg(not(windows))]
use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
use io_lifetimes::{AsFilelike, FromFilelike};
#[cfg(windows)]
use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
use std::fmt;
use std::mem::ManuallyDrop;
#[cfg(unix)]
use {
crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream},
Expand Down Expand Up @@ -883,15 +885,20 @@ impl Dir {
/// This can be useful when interacting with other libraries and or C/C++
/// code which has invoked `openat(..., O_DIRECTORY)` external to this
/// crate.
pub fn reopen_dir<Filelike: AsFilelike>(dir: &Filelike) -> io::Result<Self> {
spawn_blocking(move || {
cap_primitives::fs::open_dir(
&dir.as_filelike_view::<std::fs::File>(),
std::path::Component::CurDir.as_ref(),
)
pub async fn reopen_dir<Filelike: AsFilelike + Send>(dir: &Filelike) -> io::Result<Self> {
// Our public API has a `&Filelike` here, which prevents us from doing
// a `clone` as we usually do. So instead, we use the raw filelike, which
// we can clone and depend on it remaining open until we return.
let raw_filelike = dir.as_filelike_view::<std::fs::File>().as_raw_filelike();
// SAFETY: `raw_filelike` remains open for the duration of the
// `reopen_dir` call.
let file = ManuallyDrop::new(unsafe { std::fs::File::from_raw_filelike(raw_filelike) });
let dir = spawn_blocking(move || {
cap_primitives::fs::open_dir(&*file, std::path::Component::CurDir.as_ref())
})
.await
.map(Self::from_std_file)
.await?
.into();
Ok(Self::from_std_file(dir))
}
}

Expand Down
3 changes: 1 addition & 2 deletions cap-async-std/src/fs/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ impl File {
#[inline]
pub async fn metadata(&self) -> io::Result<Metadata> {
let clone = self.clone();
let sync = clone.std.as_filelike_view::<std::fs::File>();
spawn_blocking(move || metadata_from(&*sync)).await
spawn_blocking(move || metadata_from(&*clone.std.as_filelike_view::<std::fs::File>())).await
}

// async_std doesn't have `try_clone`.
Expand Down
2 changes: 1 addition & 1 deletion cap-async-std/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ pub use cap_primitives::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permis
// Re-export conditional types from `cap_primitives`.
#[cfg(any(unix, target_os = "vxworks", all(windows, windows_file_type_ext)))]
pub use cap_primitives::fs::FileTypeExt;
pub use cap_primitives::fs::{FileExt, OpenOptionsExt, MetadataExt};
#[cfg(unix)]
pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt};
pub use cap_primitives::fs::{FileExt, MetadataExt, OpenOptionsExt};

// Re-export things from `async_std` that we can use as-is.
#[cfg(target_os = "wasi")]
Expand Down
48 changes: 26 additions & 22 deletions cap-async-std/src/fs_utf8/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ use crate::fs_utf8::{from_utf8, to_utf8, DirBuilder, File, Metadata, ReadDir};
use async_std::{fs, io};
use camino::{Utf8Path, Utf8PathBuf};
use cap_primitives::AmbientAuthority;
use io_lifetimes::raw::{AsRawFilelike, FromRawFilelike};
use io_lifetimes::AsFilelike;
#[cfg(not(windows))]
use io_lifetimes::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
#[cfg(windows)]
use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
use std::fmt;
use std::mem::ManuallyDrop;
#[cfg(unix)]
use {
crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream},
Expand Down Expand Up @@ -170,8 +172,8 @@ impl Dir {
to_dir: &Self,
to: Q,
) -> io::Result<u64> {
let from = from_utf8(from)?;
let to = from_utf8(to)?;
let from = from_utf8(from.as_ref())?;
let to = from_utf8(to.as_ref())?;
self.cap_std.copy(from, &to_dir.cap_std, to).await
}

Expand All @@ -186,8 +188,8 @@ impl Dir {
dst_dir: &Self,
dst: Q,
) -> io::Result<()> {
let src = from_utf8(src)?;
let dst = from_utf8(dst)?;
let src = from_utf8(src.as_ref())?;
let dst = from_utf8(dst.as_ref())?;
self.cap_std.hard_link(src, &dst_dir.cap_std, dst).await
}

Expand Down Expand Up @@ -321,8 +323,8 @@ impl Dir {
to_dir: &Self,
to: Q,
) -> io::Result<()> {
let from = from_utf8(from)?;
let to = from_utf8(to)?;
let from = from_utf8(from.as_ref())?;
let to = from_utf8(to.as_ref())?;
self.cap_std.rename(from, &to_dir.cap_std, to).await
}

Expand Down Expand Up @@ -388,8 +390,8 @@ impl Dir {
original: P,
link: Q,
) -> io::Result<()> {
let original = from_utf8(original)?;
let link = from_utf8(link)?;
let original = from_utf8(original.as_ref())?;
let link = from_utf8(link.as_ref())?;
self.cap_std.symlink(original, link).await
}

Expand All @@ -416,8 +418,8 @@ impl Dir {
original: P,
link: Q,
) -> io::Result<()> {
let original = from_utf8(original)?;
let link = from_utf8(link)?;
let original = from_utf8(original.as_ref())?;
let link = from_utf8(link.as_ref())?;
self.cap_std.symlink_file(original, link).await
}

Expand All @@ -444,8 +446,8 @@ impl Dir {
original: P,
link: Q,
) -> io::Result<()> {
let original = from_utf8(original)?;
let link = from_utf8(link)?;
let original = from_utf8(original.as_ref())?;
let link = from_utf8(link.as_ref())?;
self.cap_std.symlink_dir(original, link).await
}

Expand Down Expand Up @@ -655,15 +657,17 @@ impl Dir {
/// This can be useful when interacting with other libraries and or C/C++
/// code which has invoked `openat(..., O_DIRECTORY)` external to this
/// crate.
pub fn reopen_dir<Filelike: AsFilelike>(dir: &Filelike) -> io::Result<Self> {
spawn_blocking(move || {
cap_primitives::fs::open_dir(
&dir.as_filelike_view::<std::fs::File>(),
std::path::Component::CurDir.as_ref(),
)
})
.await
.map(Self::from_std_file)
pub async fn reopen_dir<Filelike: AsFilelike>(dir: &Filelike) -> io::Result<Self> {
// Our public API has a `&Filelike` here, which prevents us from doing
// a `clone` as we usually do. So instead, we use the raw fd, which we
// can clone and depend on it remaining open until we return.
let raw_filelike = dir.as_filelike_view::<std::fs::File>().as_raw_filelike();
// SAFETY: `raw_filelike` remains open for the duration of the `reopen_dir`
// call.
let file = ManuallyDrop::new(unsafe { std::fs::File::from_raw_filelike(raw_filelike) });
crate::fs::Dir::reopen_dir(&*file)
.await
.map(Self::from_cap_std)
}
}

Expand Down
13 changes: 6 additions & 7 deletions cap-async-std/src/fs_utf8/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use async_std::task::{Context, Poll};
use camino::Utf8Path;
use cap_primitives::AmbientAuthority;
#[cfg(not(windows))]
use io_lifetimes::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
#[cfg(windows)]
use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
use std::fmt;
Expand Down Expand Up @@ -93,8 +93,7 @@ impl File {
/// This corresponds to [`async_std::fs::File::metadata`].
#[inline]
pub async fn metadata(&self) -> io::Result<Metadata> {
let clone = self.clone();
spawn_blocking(move || clone.metadata()).await
self.cap_std.metadata().await
}

// async_std doesn't have `try_clone`.
Expand All @@ -119,7 +118,7 @@ impl File {
path: P,
ambient_authority: AmbientAuthority,
) -> io::Result<Self> {
let path = from_utf8(path)?;
let path = from_utf8(path.as_ref())?;
crate::fs::File::open_ambient(path, ambient_authority)
.await
.map(Self::from_cap_std)
Expand All @@ -134,11 +133,11 @@ impl File {
/// This function is not sandboxed and may access any path that the host
/// process has access to.
#[inline]
pub async fn create_ambient<P: AsRef<Path>>(
pub async fn create_ambient<P: AsRef<Utf8Path>>(
path: P,
ambient_authority: AmbientAuthority,
) -> io::Result<Self> {
let path = from_utf8(path)?;
let path = from_utf8(path.as_ref())?;
crate::fs::File::create_ambient(path, ambient_authority)
.await
.map(Self::from_cap_std)
Expand All @@ -158,7 +157,7 @@ impl File {
options: &OpenOptions,
ambient_authority: AmbientAuthority,
) -> io::Result<Self> {
let path = from_utf8(path)?;
let path = from_utf8(path.as_ref())?;
crate::fs::File::open_ambient_with(path, options, ambient_authority)
.await
.map(Self::from_cap_std)
Expand Down
Loading

0 comments on commit f38cbd7

Please sign in to comment.