Skip to content

Commit 6a264e2

Browse files
authored
Use more custom traits. (#346)
Use custom traits instead of libstd's `OpenOptionsExt`, `FileExt`, and `DirBuilderExt`.
1 parent e3f9875 commit 6a264e2

33 files changed

+375
-92
lines changed

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

+2-2
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::MetadataExt;
43+
pub use cap_primitives::fs::{FileExt, OpenOptionsExt, MetadataExt};
4444
#[cfg(unix)]
45-
pub use cap_primitives::fs::PermissionsExt;
45+
pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt};
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/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ pub use crate::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permissions};
2525
// Re-export conditional types from `cap_primitives`.
2626
#[cfg(any(unix, target_os = "vxworks", all(windows, windows_file_type_ext)))]
2727
pub use cap_primitives::fs::FileTypeExt;
28-
pub use cap_primitives::fs::MetadataExt;
28+
pub use cap_primitives::fs::{FileExt, OpenOptionsExt, MetadataExt};
2929
#[cfg(unix)]
30-
pub use cap_primitives::fs::PermissionsExt;
30+
pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt};
3131

3232
// Re-export `camino` to make it easy for users to depend on the same
3333
// version we do, because we use its types in our public API.

cap-fs-ext/src/dir_ext.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -595,8 +595,7 @@ impl DirExt for cap_std::fs::Dir {
595595
fn remove_file_or_symlink<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
596596
use crate::OpenOptionsFollowExt;
597597
use cap_primitives::fs::_WindowsByHandle;
598-
use cap_std::fs::OpenOptions;
599-
use std::os::windows::fs::OpenOptionsExt;
598+
use cap_std::fs::{OpenOptions, OpenOptionsExt};
600599
use windows_sys::Win32::Storage::FileSystem::{
601600
DELETE, FILE_ATTRIBUTE_DIRECTORY, FILE_FLAG_BACKUP_SEMANTICS,
602601
FILE_FLAG_OPEN_REPARSE_POINT,
@@ -1092,8 +1091,7 @@ impl DirExtUtf8 for cap_std::fs_utf8::Dir {
10921091
fn remove_file_or_symlink<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
10931092
use crate::OpenOptionsFollowExt;
10941093
use cap_primitives::fs::_WindowsByHandle;
1095-
use cap_std::fs::OpenOptions;
1096-
use std::os::windows::fs::OpenOptionsExt;
1094+
use cap_std::fs::{OpenOptions, OpenOptionsExt};
10971095
use windows_sys::Win32::Storage::FileSystem::{
10981096
DELETE, FILE_ATTRIBUTE_DIRECTORY, FILE_FLAG_BACKUP_SEMANTICS,
10991097
FILE_FLAG_OPEN_REPARSE_POINT,

cap-primitives/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::env::var;
22
use std::io::Write;
33

44
fn main() {
5+
use_feature_or_nothing("unix_file_vectored_at");
56
use_feature_or_nothing("windows_by_handle"); // https://github.com/rust-lang/rust/issues/63010
67
// https://doc.rust-lang.org/unstable-book/library-features/windows-file-type-ext.html
78
use_feature_or_nothing("windows_file_type_ext");

cap-primitives/src/fs/dir_builder.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,16 @@ impl DirBuilder {
5757
}
5858
}
5959

60+
/// Unix-specific extensions to [`fs::DirBuilder`].
6061
#[cfg(unix)]
61-
impl std::os::unix::fs::DirBuilderExt for DirBuilder {
62+
pub trait DirBuilderExt {
63+
/// Sets the mode to create new directories with. This option defaults to
64+
/// 0o777.
65+
fn mode(&mut self, mode: u32) -> &mut Self;
66+
}
67+
68+
#[cfg(unix)]
69+
impl DirBuilderExt for DirBuilder {
6270
#[inline]
6371
fn mode(&mut self, mode: u32) -> &mut Self {
6472
self.options.mode(mode);

cap-primitives/src/fs/dir_options.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl DirOptions {
2525
}
2626

2727
#[cfg(unix)]
28-
impl std::os::unix::fs::DirBuilderExt for DirOptions {
28+
impl crate::fs::DirBuilderExt for DirOptions {
2929
#[inline]
3030
fn mode(&mut self, mode: u32) -> &mut Self {
3131
self.ext.mode(mode);
@@ -34,7 +34,7 @@ impl std::os::unix::fs::DirBuilderExt for DirOptions {
3434
}
3535

3636
#[cfg(target_os = "vxworks")]
37-
impl std::os::vxworks::fs::DirBuilderExt for DirOptions {
37+
impl crate::fs::DirBuilderExt for DirOptions {
3838
#[inline]
3939
fn mode(&mut self, mode: u32) -> &mut Self {
4040
self.ext.mode(mode);
@@ -46,7 +46,7 @@ impl std::os::vxworks::fs::DirBuilderExt for DirOptions {
4646
impl arbitrary::Arbitrary<'_> for DirOptions {
4747
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
4848
#[cfg(any(unix, target_os = "vxworks"))]
49-
use std::os::unix::fs::DirBuilderExt;
49+
use crate::fs::DirBuilderExt;
5050

5151
#[allow(unused_mut)]
5252
let mut dir_options = Self::new();

cap-primitives/src/fs/file.rs

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
use std::io;
2+
3+
/// Unix-specific extensions to [`fs::File`].
4+
#[cfg(unix)]
5+
pub trait FileExt {
6+
/// Reads a number of bytes starting from a given offset.
7+
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
8+
9+
/// Like `read_at`, except that it reads into a slice of buffers.
10+
#[cfg(feature = "unix_file_vectored_at")]
11+
fn read_vectored_at(
12+
&self,
13+
bufs: &mut [std::io::IoSliceMut<'_>],
14+
offset: u64,
15+
) -> io::Result<usize> {
16+
io::default_read_vectored(|b| self.read_at(b, offset), bufs)
17+
}
18+
19+
/// Reads the exact number of bytes required to fill `buf` from the given offset.
20+
fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
21+
while !buf.is_empty() {
22+
match self.read_at(buf, offset) {
23+
Ok(0) => break,
24+
Ok(n) => {
25+
let tmp = buf;
26+
buf = &mut tmp[n..];
27+
offset += n as u64;
28+
}
29+
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
30+
Err(e) => return Err(e),
31+
}
32+
}
33+
if !buf.is_empty() {
34+
Err(io::Error::new(
35+
io::ErrorKind::UnexpectedEof,
36+
"failed to fill whole buffer",
37+
))
38+
} else {
39+
Ok(())
40+
}
41+
}
42+
43+
/// Writes a number of bytes starting from a given offset.
44+
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
45+
46+
/// Like `write_at`, except that it writes from a slice of buffers.
47+
#[cfg(feature = "unix_file_vectored_at")]
48+
fn write_vectored_at(&self, bufs: &[std::io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
49+
io::default_write_vectored(|b| self.write_at(b, offset), bufs)
50+
}
51+
52+
/// Attempts to write an entire buffer starting from a given offset.
53+
fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
54+
while !buf.is_empty() {
55+
match self.write_at(buf, offset) {
56+
Ok(0) => {
57+
return Err(io::Error::new(
58+
io::ErrorKind::WriteZero,
59+
"failed to write whole buffer",
60+
));
61+
}
62+
Ok(n) => {
63+
buf = &buf[n..];
64+
offset += n as u64
65+
}
66+
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
67+
Err(e) => return Err(e),
68+
}
69+
}
70+
Ok(())
71+
}
72+
}
73+
74+
/// WASI-specific extensions to [`fs::File`].
75+
#[cfg(target_os = "wasi")]
76+
pub trait FileExt {
77+
/// Reads a number of bytes starting from a given offset.
78+
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
79+
let bufs = &mut [std::io::IoSliceMut::new(buf)];
80+
self.read_vectored_at(bufs, offset)
81+
}
82+
83+
/// Reads a number of bytes starting from a given offset.
84+
fn read_vectored_at(
85+
&self,
86+
bufs: &mut [std::io::IoSliceMut<'_>],
87+
offset: u64,
88+
) -> io::Result<usize>;
89+
90+
/// Reads the exact number of byte required to fill `buf` from the given offset.
91+
fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
92+
while !buf.is_empty() {
93+
match self.read_at(buf, offset) {
94+
Ok(0) => break,
95+
Ok(n) => {
96+
let tmp = buf;
97+
buf = &mut tmp[n..];
98+
offset += n as u64;
99+
}
100+
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
101+
Err(e) => return Err(e),
102+
}
103+
}
104+
if !buf.is_empty() {
105+
Err(io::Error::new(
106+
io::ErrorKind::UnexpectedEof,
107+
"failed to fill whole buffer",
108+
))
109+
} else {
110+
Ok(())
111+
}
112+
}
113+
114+
/// Writes a number of bytes starting from a given offset.
115+
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
116+
let bufs = &[std::io::IoSlice::new(buf)];
117+
self.write_vectored_at(bufs, offset)
118+
}
119+
120+
/// Writes a number of bytes starting from a given offset.
121+
fn write_vectored_at(&self, bufs: &[std::io::IoSlice<'_>], offset: u64) -> io::Result<usize>;
122+
123+
/// Attempts to write an entire buffer starting from a given offset.
124+
fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
125+
while !buf.is_empty() {
126+
match self.write_at(buf, offset) {
127+
Ok(0) => {
128+
return Err(io::Error::new(
129+
io::ErrorKind::WriteZero,
130+
"failed to write whole buffer",
131+
));
132+
}
133+
Ok(n) => {
134+
buf = &buf[n..];
135+
offset += n as u64
136+
}
137+
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
138+
Err(e) => return Err(e),
139+
}
140+
}
141+
Ok(())
142+
}
143+
144+
/// Returns the current position within the file.
145+
fn tell(&self) -> io::Result<u64>;
146+
147+
/// Adjust the flags associated with this file.
148+
fn fdstat_set_flags(&self, flags: u16) -> std::io::Result<()>;
149+
150+
/// Adjust the rights associated with this file.
151+
fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> std::io::Result<()>;
152+
153+
/// Provide file advisory information on a file descriptor.
154+
fn advise(&self, offset: u64, len: u64, advice: u8) -> std::io::Result<()>;
155+
156+
/// Force the allocation of space in a file.
157+
fn allocate(&self, offset: u64, len: u64) -> std::io::Result<()>;
158+
159+
/// Create a directory.
160+
fn create_directory<P: AsRef<std::path::Path>>(&self, dir: P) -> std::io::Result<()>;
161+
162+
/// Read the contents of a symbolic link.
163+
fn read_link<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<std::path::PathBuf>;
164+
165+
/// Return the attributes of a file or directory.
166+
fn metadata_at<P: AsRef<std::path::Path>>(
167+
&self,
168+
lookup_flags: u32,
169+
path: P,
170+
) -> io::Result<std::fs::Metadata>;
171+
172+
/// Unlink a file.
173+
fn remove_file<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<()>;
174+
175+
/// Remove a directory.
176+
fn remove_directory<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<()>;
177+
}
178+
179+
/// Windows-specific extensions to [`fs::File`].
180+
#[cfg(windows)]
181+
pub trait FileExt {
182+
/// Seeks to a given position and reads a number of bytes.
183+
fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
184+
185+
/// Seeks to a given position and writes a number of bytes.
186+
fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
187+
}

cap-primitives/src/fs/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod create_dir;
1111
mod dir_builder;
1212
mod dir_entry;
1313
mod dir_options;
14+
mod file;
1415
#[cfg(not(any(target_os = "android", target_os = "linux", windows)))]
1516
mod file_path_by_searching;
1617
mod file_type;
@@ -62,11 +63,12 @@ pub use access::{access, AccessModes, AccessType};
6263
pub use canonicalize::canonicalize;
6364
pub use copy::copy;
6465
pub use create_dir::create_dir;
65-
pub use dir_builder::DirBuilder;
66+
pub use dir_builder::*;
6667
pub use dir_entry::DirEntry;
6768
#[cfg(windows)]
6869
pub use dir_entry::_WindowsDirEntryExt;
6970
pub use dir_options::DirOptions;
71+
pub use file::FileExt;
7072
pub use file_type::FileType;
7173
#[cfg(any(unix, target_os = "vxworks", all(windows, windows_file_type_ext)))]
7274
pub use file_type::FileTypeExt;
@@ -81,7 +83,7 @@ pub use metadata::{Metadata, MetadataExt};
8183
pub use open::open;
8284
pub use open_ambient::open_ambient;
8385
pub use open_dir::*;
84-
pub use open_options::OpenOptions;
86+
pub use open_options::*;
8587
pub use permissions::Permissions;
8688
#[cfg(unix)]
8789
pub use permissions::PermissionsExt;

0 commit comments

Comments
 (0)