Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use more custom traits. #346

Merged
merged 2 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions 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::MetadataExt;
pub use cap_primitives::fs::{FileExt, OpenOptionsExt, MetadataExt};
#[cfg(unix)]
pub use cap_primitives::fs::PermissionsExt;
pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt};

// Re-export things from `async_std` that we can use as-is.
#[cfg(target_os = "wasi")]
Expand Down
4 changes: 2 additions & 2 deletions cap-async-std/src/fs_utf8/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ pub use crate::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permissions};
// 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::MetadataExt;
pub use cap_primitives::fs::{FileExt, OpenOptionsExt, MetadataExt};
#[cfg(unix)]
pub use cap_primitives::fs::PermissionsExt;
pub use cap_primitives::fs::{DirBuilderExt, PermissionsExt};

// Re-export `camino` to make it easy for users to depend on the same
// version we do, because we use its types in our public API.
Expand Down
6 changes: 2 additions & 4 deletions cap-fs-ext/src/dir_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,8 +595,7 @@ impl DirExt for cap_std::fs::Dir {
fn remove_file_or_symlink<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
use crate::OpenOptionsFollowExt;
use cap_primitives::fs::_WindowsByHandle;
use cap_std::fs::OpenOptions;
use std::os::windows::fs::OpenOptionsExt;
use cap_std::fs::{OpenOptions, OpenOptionsExt};
use windows_sys::Win32::Storage::FileSystem::{
DELETE, FILE_ATTRIBUTE_DIRECTORY, FILE_FLAG_BACKUP_SEMANTICS,
FILE_FLAG_OPEN_REPARSE_POINT,
Expand Down Expand Up @@ -1092,8 +1091,7 @@ impl DirExtUtf8 for cap_std::fs_utf8::Dir {
fn remove_file_or_symlink<P: AsRef<Utf8Path>>(&self, path: P) -> io::Result<()> {
use crate::OpenOptionsFollowExt;
use cap_primitives::fs::_WindowsByHandle;
use cap_std::fs::OpenOptions;
use std::os::windows::fs::OpenOptionsExt;
use cap_std::fs::{OpenOptions, OpenOptionsExt};
use windows_sys::Win32::Storage::FileSystem::{
DELETE, FILE_ATTRIBUTE_DIRECTORY, FILE_FLAG_BACKUP_SEMANTICS,
FILE_FLAG_OPEN_REPARSE_POINT,
Expand Down
1 change: 1 addition & 0 deletions cap-primitives/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::env::var;
use std::io::Write;

fn main() {
use_feature_or_nothing("unix_file_vectored_at");
use_feature_or_nothing("windows_by_handle"); // https://github.com/rust-lang/rust/issues/63010
// https://doc.rust-lang.org/unstable-book/library-features/windows-file-type-ext.html
use_feature_or_nothing("windows_file_type_ext");
Expand Down
10 changes: 9 additions & 1 deletion cap-primitives/src/fs/dir_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,16 @@ impl DirBuilder {
}
}

/// Unix-specific extensions to [`fs::DirBuilder`].
#[cfg(unix)]
impl std::os::unix::fs::DirBuilderExt for DirBuilder {
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
fn mode(&mut self, mode: u32) -> &mut Self;
}

#[cfg(unix)]
impl DirBuilderExt for DirBuilder {
#[inline]
fn mode(&mut self, mode: u32) -> &mut Self {
self.options.mode(mode);
Expand Down
6 changes: 3 additions & 3 deletions cap-primitives/src/fs/dir_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl DirOptions {
}

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

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

#[allow(unused_mut)]
let mut dir_options = Self::new();
Expand Down
187 changes: 187 additions & 0 deletions cap-primitives/src/fs/file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
use std::io;

/// Unix-specific extensions to [`fs::File`].
#[cfg(unix)]
pub trait FileExt {
/// Reads a number of bytes starting from a given offset.
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;

/// Like `read_at`, except that it reads into a slice of buffers.
#[cfg(feature = "unix_file_vectored_at")]
fn read_vectored_at(
&self,
bufs: &mut [std::io::IoSliceMut<'_>],
offset: u64,
) -> io::Result<usize> {
io::default_read_vectored(|b| self.read_at(b, offset), bufs)
}

/// Reads the exact number of bytes required to fill `buf` from the given offset.
fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
while !buf.is_empty() {
match self.read_at(buf, offset) {
Ok(0) => break,
Ok(n) => {
let tmp = buf;
buf = &mut tmp[n..];
offset += n as u64;
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
if !buf.is_empty() {
Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
))
} else {
Ok(())
}
}

/// Writes a number of bytes starting from a given offset.
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;

/// Like `write_at`, except that it writes from a slice of buffers.
#[cfg(feature = "unix_file_vectored_at")]
fn write_vectored_at(&self, bufs: &[std::io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
io::default_write_vectored(|b| self.write_at(b, offset), bufs)
}

/// Attempts to write an entire buffer starting from a given offset.
fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
while !buf.is_empty() {
match self.write_at(buf, offset) {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write whole buffer",
));
}
Ok(n) => {
buf = &buf[n..];
offset += n as u64
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}
}

/// WASI-specific extensions to [`fs::File`].
#[cfg(target_os = "wasi")]
pub trait FileExt {
/// Reads a number of bytes starting from a given offset.
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
let bufs = &mut [std::io::IoSliceMut::new(buf)];
self.read_vectored_at(bufs, offset)
}

/// Reads a number of bytes starting from a given offset.
fn read_vectored_at(
&self,
bufs: &mut [std::io::IoSliceMut<'_>],
offset: u64,
) -> io::Result<usize>;

/// Reads the exact number of byte required to fill `buf` from the given offset.
fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
while !buf.is_empty() {
match self.read_at(buf, offset) {
Ok(0) => break,
Ok(n) => {
let tmp = buf;
buf = &mut tmp[n..];
offset += n as u64;
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
if !buf.is_empty() {
Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
))
} else {
Ok(())
}
}

/// Writes a number of bytes starting from a given offset.
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
let bufs = &[std::io::IoSlice::new(buf)];
self.write_vectored_at(bufs, offset)
}

/// Writes a number of bytes starting from a given offset.
fn write_vectored_at(&self, bufs: &[std::io::IoSlice<'_>], offset: u64) -> io::Result<usize>;

/// Attempts to write an entire buffer starting from a given offset.
fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
while !buf.is_empty() {
match self.write_at(buf, offset) {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write whole buffer",
));
}
Ok(n) => {
buf = &buf[n..];
offset += n as u64
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}

/// Returns the current position within the file.
fn tell(&self) -> io::Result<u64>;

/// Adjust the flags associated with this file.
fn fdstat_set_flags(&self, flags: u16) -> std::io::Result<()>;

/// Adjust the rights associated with this file.
fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> std::io::Result<()>;

/// Provide file advisory information on a file descriptor.
fn advise(&self, offset: u64, len: u64, advice: u8) -> std::io::Result<()>;

/// Force the allocation of space in a file.
fn allocate(&self, offset: u64, len: u64) -> std::io::Result<()>;

/// Create a directory.
fn create_directory<P: AsRef<std::path::Path>>(&self, dir: P) -> std::io::Result<()>;

/// Read the contents of a symbolic link.
fn read_link<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<std::path::PathBuf>;

/// Return the attributes of a file or directory.
fn metadata_at<P: AsRef<std::path::Path>>(
&self,
lookup_flags: u32,
path: P,
) -> io::Result<std::fs::Metadata>;

/// Unlink a file.
fn remove_file<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<()>;

/// Remove a directory.
fn remove_directory<P: AsRef<std::path::Path>>(&self, path: P) -> io::Result<()>;
}

/// Windows-specific extensions to [`fs::File`].
#[cfg(windows)]
pub trait FileExt {
/// Seeks to a given position and reads a number of bytes.
fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;

/// Seeks to a given position and writes a number of bytes.
fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
}
6 changes: 4 additions & 2 deletions cap-primitives/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod create_dir;
mod dir_builder;
mod dir_entry;
mod dir_options;
mod file;
#[cfg(not(any(target_os = "android", target_os = "linux", windows)))]
mod file_path_by_searching;
mod file_type;
Expand Down Expand Up @@ -62,11 +63,12 @@ pub use access::{access, AccessModes, AccessType};
pub use canonicalize::canonicalize;
pub use copy::copy;
pub use create_dir::create_dir;
pub use dir_builder::DirBuilder;
pub use dir_builder::*;
pub use dir_entry::DirEntry;
#[cfg(windows)]
pub use dir_entry::_WindowsDirEntryExt;
pub use dir_options::DirOptions;
pub use file::FileExt;
pub use file_type::FileType;
#[cfg(any(unix, target_os = "vxworks", all(windows, windows_file_type_ext)))]
pub use file_type::FileTypeExt;
Expand All @@ -81,7 +83,7 @@ pub use metadata::{Metadata, MetadataExt};
pub use open::open;
pub use open_ambient::open_ambient;
pub use open_dir::*;
pub use open_options::OpenOptions;
pub use open_options::*;
pub use permissions::Permissions;
#[cfg(unix)]
pub use permissions::PermissionsExt;
Expand Down
Loading