Skip to content

Commit c374981

Browse files
committed
Add an IsReadWrite trait to expose cap_primitives::fs::is_read_write.
1 parent f9de022 commit c374981

File tree

10 files changed

+139
-20
lines changed

10 files changed

+139
-20
lines changed

Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,14 @@ winx = "0.22.0"
4040

4141
[features]
4242
default = []
43-
fs_utf8 = ["cap-std/fs_utf8", "cap-async-std/fs_utf8"]
43+
fs_utf8 = [
44+
"cap-std/fs_utf8",
45+
"cap-fs-ext/fs_utf8",
46+
]
47+
async_std_fs_utf8 = [
48+
"cap-async-std/fs_utf8",
49+
"cap-fs-ext/async_std_fs_utf8"
50+
]
4451

4552
[badges]
4653
maintenance = { status = "actively-developed" }

cap-async-std/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ async-std = { version = "1.8.0", features = ["attributes"] }
1919
cap-primitives = { path = "../cap-primitives", version = "^0.10.1-alpha.0"}
2020
unsafe-io = "0.2.0"
2121

22-
[badges]
23-
maintenance = { status = "actively-developed" }
24-
2522
[features]
2623
default = []
2724
fs_utf8 = ["arf-strings"]
25+
26+
[badges]
27+
maintenance = { status = "actively-developed" }

cap-fs-ext/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ unsafe-io = "0.2.0"
2323

2424
[features]
2525
default = ["std"]
26-
fs_utf8 = ["arf-strings", "cap-std/fs_utf8", "cap-async-std/fs_utf8"]
26+
fs_utf8 = ["arf-strings", "cap-std/fs_utf8"]
2727
std = ["cap-std"]
2828
async_std = ["cap-async-std", "async-std"]
29+
async_std_fs_utf8 = ["cap-async-std/fs_utf8"]
2930

3031
[badges]
3132
maintenance = { status = "actively-developed" }

cap-fs-ext/src/is_read_write.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use cap_primitives::fs::is_read_write;
2+
use std::io;
3+
use unsafe_io::AsUnsafeFile;
4+
5+
/// A trait for the `is_read_write` function for `File` types.
6+
///
7+
/// This is only implemented for `File` types; for arbitrary I/O handles, use
8+
/// [`system_interface::io::IsReadWrite`] instead.
9+
///
10+
/// [`system_interface::io::IsReadWrite`]: https://docs.rs/system-interface/latest/system_interface/io/trait.ReadReady.html
11+
pub trait IsReadWrite {
12+
/// Test whether the given file is readable and/or writable.
13+
fn is_read_write(&self) -> io::Result<(bool, bool)>;
14+
}
15+
16+
impl IsReadWrite for std::fs::File {
17+
#[inline]
18+
fn is_read_write(&self) -> io::Result<(bool, bool)> {
19+
is_read_write(self)
20+
}
21+
}
22+
23+
#[cfg(all(feature = "std"))]
24+
impl IsReadWrite for cap_std::fs::File {
25+
#[inline]
26+
fn is_read_write(&self) -> io::Result<(bool, bool)> {
27+
is_read_write(&self.as_file_view())
28+
}
29+
}
30+
31+
#[cfg(all(feature = "std", feature = "fs_utf8"))]
32+
impl IsReadWrite for cap_std::fs_utf8::File {
33+
#[inline]
34+
fn is_read_write(&self) -> io::Result<(bool, bool)> {
35+
is_read_write(&self.as_file_view())
36+
}
37+
}
38+
39+
#[cfg(all(feature = "async_std"))]
40+
impl IsReadWrite for async_std::fs::File {
41+
#[inline]
42+
fn is_read_write(&self) -> io::Result<(bool, bool)> {
43+
is_read_write(&self.as_file_view())
44+
}
45+
}
46+
47+
#[cfg(all(feature = "async_std"))]
48+
impl IsReadWrite for cap_async_std::fs::File {
49+
#[inline]
50+
fn is_read_write(&self) -> io::Result<(bool, bool)> {
51+
is_read_write(&self.as_file_view())
52+
}
53+
}
54+
55+
#[cfg(all(feature = "async_std", feature = "fs_utf8"))]
56+
impl IsReadWrite for cap_async_std::fs_utf8::File {
57+
#[inline]
58+
fn is_read_write(&self) -> io::Result<(bool, bool)> {
59+
is_read_write(&self.as_file_view())
60+
}
61+
}

cap-fs-ext/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
mod dir_ext;
1313
mod file_type_ext;
14+
mod is_read_write;
1415
mod metadata_ext;
1516
mod open_options_follow_ext;
1617
mod reopen;
@@ -19,6 +20,7 @@ mod reopen;
1920
pub use dir_ext::DirExtUtf8;
2021
pub use dir_ext::{DirExt, SystemTimeSpec};
2122
pub use file_type_ext::FileTypeExt;
23+
pub use is_read_write::IsReadWrite;
2224
pub use metadata_ext::MetadataExt;
2325
pub use open_options_follow_ext::{FollowSymlinks, OpenOptionsFollowExt};
2426
pub use reopen::Reopen;

cap-fs-ext/src/reopen.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,23 @@ impl Reopen for cap_std::fs_utf8::File {
5353
}
5454
}
5555

56+
#[cfg(feature = "async_std")]
57+
impl Reopen for async_std::fs::File {
58+
#[inline]
59+
fn reopen(&self, options: &OpenOptions) -> io::Result<Self> {
60+
let file = reopen(&self.as_file_view(), options)?;
61+
let unsafe_file = file.into_unsafe_file();
62+
Ok(unsafe { async_std::fs::File::from_unsafe_file(unsafe_file) })
63+
}
64+
}
65+
5666
#[cfg(feature = "async_std")]
5767
impl Reopen for cap_async_std::fs::File {
5868
#[inline]
5969
fn reopen(&self, options: &OpenOptions) -> io::Result<Self> {
6070
let file = reopen(&self.as_file_view(), options)?;
61-
Ok(unsafe {
62-
Self::from_std(async_std::fs::File::from_unsafe_file(
63-
file.into_unsafe_file(),
64-
))
65-
})
71+
let unsafe_file = file.into_unsafe_file();
72+
Ok(unsafe { Self::from_std(async_std::fs::File::from_unsafe_file(unsafe_file)) })
6673
}
6774
}
6875

@@ -71,10 +78,7 @@ impl Reopen for cap_async_std::fs_utf8::File {
7178
#[inline]
7279
fn reopen(&self, options: &OpenOptions) -> io::Result<Self> {
7380
let file = reopen(&self.as_file_view(), options)?;
74-
Ok(unsafe {
75-
Self::from_std(async_std::fs::File::from_unsafe_file(
76-
file.into_unsafe_file(),
77-
))
78-
})
81+
let unsafe_file = file.into_unsafe_file();
82+
Ok(unsafe { Self::from_std(async_std::fs::File::from_unsafe_file(unsafe_file)) })
7983
}
8084
}

cap-primitives/src/windows/fs/is_read_write_impl.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub(crate) fn is_read_write_impl(file: &fs::File) -> io::Result<(bool, bool)> {
44
let handle = file.as_raw_handle();
55
let access_mode = winx::file::query_access_information(handle)?;
66
let read = access_mode.contains(winx::file::AccessMode::FILE_READ_DATA);
7-
let write = access_mode.contains(winx::file::AccessMode::FILE_WRITE_DATA);
7+
let write = access_mode.contains(winx::file::AccessMode::FILE_WRITE_DATA)
8+
|| access_mode.contains(winx::file::AccessMode::FILE_APPEND_DATA);
89
Ok((read, write))
910
}

cap-std/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ arf-strings = { version = "0.3.0", optional = true }
1818
cap-primitives = { path = "../cap-primitives", version = "^0.10.1-alpha.0"}
1919
unsafe-io = "0.2.0"
2020

21-
[badges]
22-
maintenance = { status = "actively-developed" }
23-
2421
[features]
2522
default = []
2623
fs_utf8 = ["arf-strings"]
24+
25+
[badges]
26+
maintenance = { status = "actively-developed" }

cap-time-ext/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ posish = "0.5.2"
2222

2323
[target.'cfg(windows)'.dependencies]
2424
once_cell = "1.5.2"
25-
winx = "0.21.0"
25+
winx = "0.22.0"
2626

2727
[badges]
2828
maintenance = { status = "actively-developed" }

tests/is-read-write.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#[macro_use]
2+
mod sys_common;
3+
4+
use cap_fs_ext::{IsReadWrite, OpenOptions};
5+
use sys_common::io::tmpdir;
6+
7+
#[test]
8+
fn basic_is_read_write() {
9+
let tmpdir = tmpdir();
10+
11+
let file = check!(tmpdir.open_with(
12+
"file",
13+
OpenOptions::new()
14+
.create(true)
15+
.truncate(true)
16+
.write(true)
17+
.read(true)
18+
));
19+
assert_eq!(check!(file.is_read_write()), (true, true));
20+
21+
let file = check!(tmpdir.open_with("file", OpenOptions::new().append(true).read(true)));
22+
assert_eq!(check!(file.is_read_write()), (true, true));
23+
24+
let file = check!(tmpdir.open_with(
25+
"file",
26+
OpenOptions::new()
27+
.create(true)
28+
.truncate(true)
29+
.write(true)
30+
.read(false)
31+
));
32+
assert_eq!(check!(file.is_read_write()), (false, true));
33+
34+
let file = check!(tmpdir.open_with(
35+
"file",
36+
OpenOptions::new()
37+
.create(false)
38+
.truncate(false)
39+
.write(false)
40+
.read(true)
41+
));
42+
assert_eq!(check!(file.is_read_write()), (true, false));
43+
}

0 commit comments

Comments
 (0)