Skip to content

Commit f38cbd7

Browse files
authored
Reenable cap-async-std. (#370)
* 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.
1 parent ef0c8ac commit f38cbd7

File tree

18 files changed

+329
-111
lines changed

18 files changed

+329
-111
lines changed

Cargo.toml

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ exclude = ["/.*"]
1717
rust-version = "1.63"
1818

1919
[dev-dependencies]
20-
#async-std = { version = "1.10.0", features = ["attributes"] }
20+
async-std = { version = "1.13.0", features = ["attributes", "io_safety"] }
2121
anyhow = "1.0.37"
22-
#cap-async-std = { path = "cap-async-std", version = "^0.25.0" }
23-
cap-fs-ext = { path = "cap-fs-ext", version = "^3.3.0" }
24-
cap-net-ext = { path = "cap-net-ext", version = "^3.3.0" }
25-
cap-directories = { path = "cap-directories", version = "^3.3.0" }
26-
cap-std = { path = "cap-std", version = "^3.3.0" }
27-
cap-tempfile = { path = "cap-tempfile", version = "^3.3.0" }
28-
cap-rand = { path = "cap-rand", version = "^3.3.0" }
22+
cap-async-std = { path = "cap-async-std", version = "3.3.0" }
23+
cap-fs-ext = { path = "cap-fs-ext", version = "3.3.0" }
24+
cap-net-ext = { path = "cap-net-ext", version = "3.3.0" }
25+
cap-directories = { path = "cap-directories", version = "3.3.0" }
26+
cap-std = { path = "cap-std", version = "3.3.0" }
27+
cap-tempfile = { path = "cap-tempfile", version = "3.3.0" }
28+
cap-rand = { path = "cap-rand", version = "3.3.0" }
2929
rand = "0.8.1"
3030
tempfile = "3.1.0"
3131
camino = "1.0.5"
@@ -55,23 +55,23 @@ fs_utf8 = [
5555
"cap-fs-ext/fs_utf8",
5656
"cap-tempfile/fs_utf8",
5757
]
58-
#async_std_fs_utf8 = [
59-
# "cap-async-std/fs_utf8",
60-
# "cap-fs-ext/async_std_fs_utf8"
61-
#]
58+
async_std_fs_utf8 = [
59+
"cap-async-std/fs_utf8",
60+
"cap-fs-ext/async_std_fs_utf8"
61+
]
6262
arf_strings = [
6363
"cap-std/arf_strings",
6464
"cap-fs-ext/arf_strings",
6565
"cap-tempfile/arf_strings",
6666
]
67-
#async_std_arf_strings = [
68-
# "cap-async-std/arf_strings",
69-
# "cap-fs-ext/async_std_arf_strings"
70-
#]
67+
async_std_arf_strings = [
68+
"cap-async-std/arf_strings",
69+
"cap-fs-ext/async_std_arf_strings"
70+
]
7171

7272
[workspace]
7373
members = [
74-
#"cap-async-std",
74+
"cap-async-std",
7575
"cap-fs-ext",
7676
"cap-net-ext",
7777
"cap-directories",

cap-async-std/Cargo.toml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cap-async-std"
3-
version = "0.25.2"
3+
version = "3.3.0"
44
description = "Capability-based version of async-std"
55
authors = [
66
"Dan Gohman <[email protected]>",
@@ -11,15 +11,13 @@ keywords = ["network", "file", "async", "future", "await"]
1111
categories = ["filesystem", "network-programming", "asynchronous", "concurrency"]
1212
repository = "https://github.com/bytecodealliance/cap-std"
1313
edition = "2021"
14-
publish = false # temporary, until async-rs/async-std#1036 is available
1514

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

2523
[target.'cfg(not(windows))'.dependencies]

cap-async-std/build.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use std::env::var;
2+
use std::io::Write;
3+
4+
fn main() {
5+
use_feature_or_nothing("windows_file_type_ext");
6+
7+
// Cfgs that users may set.
8+
println!("cargo:rustc-check-cfg=cfg(io_lifetimes_use_std)");
9+
10+
// Don't rerun this on changes other than build.rs, as we only depend on
11+
// the rustc version.
12+
println!("cargo:rerun-if-changed=build.rs");
13+
}
14+
15+
fn use_feature_or_nothing(feature: &str) {
16+
if has_feature(feature) {
17+
use_feature(feature);
18+
}
19+
println!("cargo:rustc-check-cfg=cfg({})", feature);
20+
}
21+
22+
fn use_feature(feature: &str) {
23+
println!("cargo:rustc-cfg={}", feature);
24+
}
25+
26+
/// Test whether the rustc at `var("RUSTC")` supports the given feature.
27+
fn has_feature(feature: &str) -> bool {
28+
can_compile(&format!(
29+
"#![allow(stable_features)]\n#![feature({})]",
30+
feature
31+
))
32+
}
33+
34+
/// Test whether the rustc at `var("RUSTC")` can compile the given code.
35+
fn can_compile<T: AsRef<str>>(test: T) -> bool {
36+
use std::process::Stdio;
37+
38+
let out_dir = var("OUT_DIR").unwrap();
39+
let rustc = var("RUSTC").unwrap();
40+
let target = var("TARGET").unwrap();
41+
42+
// Use `RUSTC_WRAPPER` if it's set, unless it's set to an empty string,
43+
// as documented [here].
44+
// [here]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-reads
45+
let wrapper = var("RUSTC_WRAPPER")
46+
.ok()
47+
.and_then(|w| if w.is_empty() { None } else { Some(w) });
48+
49+
let mut cmd = if let Some(wrapper) = wrapper {
50+
let mut cmd = std::process::Command::new(wrapper);
51+
// The wrapper's first argument is supposed to be the path to rustc.
52+
cmd.arg(rustc);
53+
cmd
54+
} else {
55+
std::process::Command::new(rustc)
56+
};
57+
58+
cmd.arg("--crate-type=rlib") // Don't require `main`.
59+
.arg("--emit=metadata") // Do as little as possible but still parse.
60+
.arg("--target")
61+
.arg(target)
62+
.arg("--out-dir")
63+
.arg(out_dir); // Put the output somewhere inconsequential.
64+
65+
// If Cargo wants to set RUSTFLAGS, use that.
66+
if let Ok(rustflags) = var("CARGO_ENCODED_RUSTFLAGS") {
67+
if !rustflags.is_empty() {
68+
for arg in rustflags.split('\x1f') {
69+
cmd.arg(arg);
70+
}
71+
}
72+
}
73+
74+
let mut child = cmd
75+
.arg("-") // Read from stdin.
76+
.stdin(Stdio::piped()) // Stdin is a pipe.
77+
.stderr(Stdio::null()) // Errors from feature detection aren't interesting and can be confusing.
78+
.spawn()
79+
.unwrap();
80+
81+
writeln!(child.stdin.take().unwrap(), "{}", test.as_ref()).unwrap();
82+
83+
child.wait().unwrap().success()
84+
}

cap-async-std/src/fs/dir.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ use cap_primitives::fs::{
1313
remove_open_dir_all, rename, set_permissions, stat, DirOptions, FollowSymlinks, Permissions,
1414
};
1515
use cap_primitives::AmbientAuthority;
16+
use io_lifetimes::raw::{AsRawFilelike, FromRawFilelike};
1617
#[cfg(not(windows))]
1718
use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
1819
use io_lifetimes::{AsFilelike, FromFilelike};
1920
#[cfg(windows)]
2021
use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
2122
use std::fmt;
23+
use std::mem::ManuallyDrop;
2224
#[cfg(unix)]
2325
use {
2426
crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream},
@@ -883,15 +885,20 @@ impl Dir {
883885
/// This can be useful when interacting with other libraries and or C/C++
884886
/// code which has invoked `openat(..., O_DIRECTORY)` external to this
885887
/// crate.
886-
pub fn reopen_dir<Filelike: AsFilelike>(dir: &Filelike) -> io::Result<Self> {
887-
spawn_blocking(move || {
888-
cap_primitives::fs::open_dir(
889-
&dir.as_filelike_view::<std::fs::File>(),
890-
std::path::Component::CurDir.as_ref(),
891-
)
888+
pub async fn reopen_dir<Filelike: AsFilelike + Send>(dir: &Filelike) -> io::Result<Self> {
889+
// Our public API has a `&Filelike` here, which prevents us from doing
890+
// a `clone` as we usually do. So instead, we use the raw filelike, which
891+
// we can clone and depend on it remaining open until we return.
892+
let raw_filelike = dir.as_filelike_view::<std::fs::File>().as_raw_filelike();
893+
// SAFETY: `raw_filelike` remains open for the duration of the
894+
// `reopen_dir` call.
895+
let file = ManuallyDrop::new(unsafe { std::fs::File::from_raw_filelike(raw_filelike) });
896+
let dir = spawn_blocking(move || {
897+
cap_primitives::fs::open_dir(&*file, std::path::Component::CurDir.as_ref())
892898
})
893-
.await
894-
.map(Self::from_std_file)
899+
.await?
900+
.into();
901+
Ok(Self::from_std_file(dir))
895902
}
896903
}
897904

cap-async-std/src/fs/file.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ impl File {
9090
#[inline]
9191
pub async fn metadata(&self) -> io::Result<Metadata> {
9292
let clone = self.clone();
93-
let sync = clone.std.as_filelike_view::<std::fs::File>();
94-
spawn_blocking(move || metadata_from(&*sync)).await
93+
spawn_blocking(move || metadata_from(&*clone.std.as_filelike_view::<std::fs::File>())).await
9594
}
9695

9796
// async_std doesn't have `try_clone`.

cap-async-std/src/fs/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ pub use cap_primitives::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permis
4040
// Re-export conditional types from `cap_primitives`.
4141
#[cfg(any(unix, target_os = "vxworks", all(windows, windows_file_type_ext)))]
4242
pub use cap_primitives::fs::FileTypeExt;
43-
pub use cap_primitives::fs::{FileExt, OpenOptionsExt, MetadataExt};
4443
#[cfg(unix)]
4544
pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt};
45+
pub use cap_primitives::fs::{FileExt, MetadataExt, OpenOptionsExt};
4646

4747
// Re-export things from `async_std` that we can use as-is.
4848
#[cfg(target_os = "wasi")]

cap-async-std/src/fs_utf8/dir.rs

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ use crate::fs_utf8::{from_utf8, to_utf8, DirBuilder, File, Metadata, ReadDir};
33
use async_std::{fs, io};
44
use camino::{Utf8Path, Utf8PathBuf};
55
use cap_primitives::AmbientAuthority;
6+
use io_lifetimes::raw::{AsRawFilelike, FromRawFilelike};
67
use io_lifetimes::AsFilelike;
78
#[cfg(not(windows))]
8-
use io_lifetimes::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
9+
use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
910
#[cfg(windows)]
1011
use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
1112
use std::fmt;
13+
use std::mem::ManuallyDrop;
1214
#[cfg(unix)]
1315
use {
1416
crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream},
@@ -170,8 +172,8 @@ impl Dir {
170172
to_dir: &Self,
171173
to: Q,
172174
) -> io::Result<u64> {
173-
let from = from_utf8(from)?;
174-
let to = from_utf8(to)?;
175+
let from = from_utf8(from.as_ref())?;
176+
let to = from_utf8(to.as_ref())?;
175177
self.cap_std.copy(from, &to_dir.cap_std, to).await
176178
}
177179

@@ -186,8 +188,8 @@ impl Dir {
186188
dst_dir: &Self,
187189
dst: Q,
188190
) -> io::Result<()> {
189-
let src = from_utf8(src)?;
190-
let dst = from_utf8(dst)?;
191+
let src = from_utf8(src.as_ref())?;
192+
let dst = from_utf8(dst.as_ref())?;
191193
self.cap_std.hard_link(src, &dst_dir.cap_std, dst).await
192194
}
193195

@@ -321,8 +323,8 @@ impl Dir {
321323
to_dir: &Self,
322324
to: Q,
323325
) -> io::Result<()> {
324-
let from = from_utf8(from)?;
325-
let to = from_utf8(to)?;
326+
let from = from_utf8(from.as_ref())?;
327+
let to = from_utf8(to.as_ref())?;
326328
self.cap_std.rename(from, &to_dir.cap_std, to).await
327329
}
328330

@@ -388,8 +390,8 @@ impl Dir {
388390
original: P,
389391
link: Q,
390392
) -> io::Result<()> {
391-
let original = from_utf8(original)?;
392-
let link = from_utf8(link)?;
393+
let original = from_utf8(original.as_ref())?;
394+
let link = from_utf8(link.as_ref())?;
393395
self.cap_std.symlink(original, link).await
394396
}
395397

@@ -416,8 +418,8 @@ impl Dir {
416418
original: P,
417419
link: Q,
418420
) -> io::Result<()> {
419-
let original = from_utf8(original)?;
420-
let link = from_utf8(link)?;
421+
let original = from_utf8(original.as_ref())?;
422+
let link = from_utf8(link.as_ref())?;
421423
self.cap_std.symlink_file(original, link).await
422424
}
423425

@@ -444,8 +446,8 @@ impl Dir {
444446
original: P,
445447
link: Q,
446448
) -> io::Result<()> {
447-
let original = from_utf8(original)?;
448-
let link = from_utf8(link)?;
449+
let original = from_utf8(original.as_ref())?;
450+
let link = from_utf8(link.as_ref())?;
449451
self.cap_std.symlink_dir(original, link).await
450452
}
451453

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

cap-async-std/src/fs_utf8/file.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use async_std::task::{Context, Poll};
1010
use camino::Utf8Path;
1111
use cap_primitives::AmbientAuthority;
1212
#[cfg(not(windows))]
13-
use io_lifetimes::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
13+
use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
1414
#[cfg(windows)]
1515
use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
1616
use std::fmt;
@@ -93,8 +93,7 @@ impl File {
9393
/// This corresponds to [`async_std::fs::File::metadata`].
9494
#[inline]
9595
pub async fn metadata(&self) -> io::Result<Metadata> {
96-
let clone = self.clone();
97-
spawn_blocking(move || clone.metadata()).await
96+
self.cap_std.metadata().await
9897
}
9998

10099
// async_std doesn't have `try_clone`.
@@ -119,7 +118,7 @@ impl File {
119118
path: P,
120119
ambient_authority: AmbientAuthority,
121120
) -> io::Result<Self> {
122-
let path = from_utf8(path)?;
121+
let path = from_utf8(path.as_ref())?;
123122
crate::fs::File::open_ambient(path, ambient_authority)
124123
.await
125124
.map(Self::from_cap_std)
@@ -134,11 +133,11 @@ impl File {
134133
/// This function is not sandboxed and may access any path that the host
135134
/// process has access to.
136135
#[inline]
137-
pub async fn create_ambient<P: AsRef<Path>>(
136+
pub async fn create_ambient<P: AsRef<Utf8Path>>(
138137
path: P,
139138
ambient_authority: AmbientAuthority,
140139
) -> io::Result<Self> {
141-
let path = from_utf8(path)?;
140+
let path = from_utf8(path.as_ref())?;
142141
crate::fs::File::create_ambient(path, ambient_authority)
143142
.await
144143
.map(Self::from_cap_std)
@@ -158,7 +157,7 @@ impl File {
158157
options: &OpenOptions,
159158
ambient_authority: AmbientAuthority,
160159
) -> io::Result<Self> {
161-
let path = from_utf8(path)?;
160+
let path = from_utf8(path.as_ref())?;
162161
crate::fs::File::open_ambient_with(path, options, ambient_authority)
163162
.await
164163
.map(Self::from_cap_std)

0 commit comments

Comments
 (0)