diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs
index 5992766b5a42d..a4f6ce406cb05 100644
--- a/library/std/src/sys/fs/hermit.rs
+++ b/library/std/src/sys/fs/hermit.rs
@@ -1,3 +1,5 @@
+use alloc_crate::borrow::Cow;
+
use crate::ffi::{CStr, OsStr, OsString, c_char};
use crate::fs::TryLockError;
use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
@@ -53,6 +55,37 @@ impl ReadDir {
}
}
+/// Specialization trait used to construct a `ReadDir`
+trait ReadDirFromPath
{
+ fn from_path(dir: Vec, path: P) -> Self;
+}
+
+impl> ReadDirFromPath for ReadDir {
+ default fn from_path(dir: Vec, path: P) -> Self {
+ let inner = InnerReadDir { root: path.as_ref().to_path_buf(), dir };
+ ReadDir::new(inner)
+ }
+}
+
+/// This constructs a `ReadDir` for all types that can be converted
+/// into `PathBuf` without allocating
+macro_rules! impl_read_dir_from_path {
+ ($t:ty) => {
+ impl ReadDirFromPath<$t> for ReadDir {
+ fn from_path(dir: Vec, path: $t) -> Self {
+ let inner = InnerReadDir::new(path.into(), dir);
+ ReadDir::new(inner)
+ }
+ }
+ };
+}
+
+impl_read_dir_from_path!(PathBuf);
+impl_read_dir_from_path!(Box);
+impl_read_dir_from_path!(Cow<'_, Path>);
+impl_read_dir_from_path!(OsString);
+impl_read_dir_from_path!(String);
+
pub struct DirEntry {
/// path to the entry
root: PathBuf,
@@ -512,12 +545,11 @@ impl FromRawFd for File {
}
}
-pub fn readdir(path: &Path) -> io::Result {
- let fd_raw = run_path_with_cstr(path, &|path| {
+pub fn readdir>(path: P) -> io::Result {
+ let fd_raw = run_path_with_cstr(path.as_ref(), &|path| {
cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) })
})?;
let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) };
- let root = path.to_path_buf();
// read all director entries
let mut vec: Vec = Vec::new();
@@ -551,7 +583,7 @@ pub fn readdir(path: &Path) -> io::Result {
}
}
- Ok(ReadDir::new(InnerReadDir::new(root, vec)))
+ Ok(>::from_path(vec, path))
}
pub fn unlink(path: &Path) -> io::Result<()> {
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
index 0c297c5766b82..be99643219ab4 100644
--- a/library/std/src/sys/fs/mod.rs
+++ b/library/std/src/sys/fs/mod.rs
@@ -63,7 +63,7 @@ pub use imp::{
ReadDir,
};
-pub fn read_dir(path: &Path) -> io::Result {
+pub fn read_dir>(path: P) -> io::Result {
// FIXME: use with_native_path on all platforms
imp::readdir(path)
}
diff --git a/library/std/src/sys/fs/motor.rs b/library/std/src/sys/fs/motor.rs
index 2ae01db24be5c..d6ec5b7fcfe8f 100644
--- a/library/std/src/sys/fs/motor.rs
+++ b/library/std/src/sys/fs/motor.rs
@@ -1,3 +1,5 @@
+use alloc_crate::borrow::Cow;
+
use crate::ffi::OsString;
use crate::hash::Hash;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
@@ -377,12 +379,49 @@ impl Drop for ReadDir {
}
}
-pub fn readdir(path: &Path) -> io::Result {
- let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
- Ok(ReadDir {
- rt_fd: moto_rt::fs::opendir(path).map_err(map_motor_error)?,
- path: path.to_owned(),
- })
+/// Specialization trait used to construct a `ReadDir`
+trait ReadDirFromPath {
+ fn from_path(path: P) -> io::Result;
+}
+
+impl> ReadDirFromPath for ReadDir {
+ default fn from_path(path: P) -> io::Result {
+ let path = path.as_ref().to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+ Ok(ReadDir {
+ rt_fd: moto_rt::fs::opendir(path).map_err(map_motor_error)?,
+ path: path.to_owned(),
+ })
+ }
+}
+
+/// This constructs a `ReadDir` for all types that can be converted
+/// into `String` without allocating
+macro_rules! impl_read_dir_from_path {
+ ($t:ty) => {
+ impl ReadDirFromPath<$t> for ReadDir {
+ fn from_path(path: $t) -> io::Result {
+ let path_buf: PathBuf = path.into();
+ let path = path_buf.into_os_string().into_string();
+ match path {
+ Err(_) => return Err(io::Error::from(io::ErrorKind::InvalidFilename)),
+ Ok(path) => Ok(ReadDir {
+ rt_fd: moto_rt::fs::opendir(path).map_err(map_motor_error)?,
+ path,
+ }),
+ }
+ }
+ }
+ };
+}
+
+impl_read_dir_from_path!(PathBuf);
+impl_read_dir_from_path!(Box);
+impl_read_dir_from_path!(Cow<'_, Path>);
+impl_read_dir_from_path!(OsString);
+impl_read_dir_from_path!(String);
+
+pub fn readdir>(path: P) -> io::Result {
+ >::from_path(path)
}
impl Iterator for ReadDir {
diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs
index f15a152146ee5..3b783e466f826 100644
--- a/library/std/src/sys/fs/solid.rs
+++ b/library/std/src/sys/fs/solid.rs
@@ -1,5 +1,7 @@
#![allow(dead_code)]
+use alloc_crate::borrow::Cow;
+
use crate::ffi::{CStr, CString, OsStr, OsString};
use crate::fmt;
use crate::fs::TryLockError;
@@ -146,19 +148,49 @@ impl FileType {
}
}
-pub fn readdir(p: &Path) -> io::Result {
+pub fn readdir>(p: P) -> io::Result {
unsafe {
let mut dir = MaybeUninit::uninit();
error::SolidError::err_if_negative(abi::SOLID_FS_OpenDir(
- cstr(p)?.as_ptr(),
+ cstr(p.as_ref())?.as_ptr(),
dir.as_mut_ptr(),
))
.map_err(|e| e.as_io_error())?;
- let inner = Arc::new(InnerReadDir { dirp: dir.assume_init(), root: p.to_owned() });
- Ok(ReadDir { inner })
+ Ok(>::from_path(dir.assume_init(), p))
+ }
+}
+
+/// Specialization trait used to construct a `ReadDir`
+trait ReadDirFromPath {
+ fn from_path(dirp: abi::S_DIR, path: P) -> Self;
+}
+
+impl> ReadDirFromPath for ReadDir {
+ default fn from_path(dirp: abi::S_DIR, path: P) -> Self {
+ let inner = InnerReadDir { dirp, root: path.as_ref().to_path_buf() };
+ ReadDir { inner: Arc::new(inner) }
}
}
+/// This constructs a `ReadDir` for all types that can be converted
+/// into `PathBuf` without allocating
+macro_rules! impl_read_dir_from_path {
+ ($t:ty) => {
+ impl ReadDirFromPath<$t> for ReadDir {
+ fn from_path(dirp: abi::S_DIR, path: $t) -> Self {
+ let inner = InnerReadDir { dirp, root: path.into() };
+ ReadDir { inner: Arc::new(inner) }
+ }
+ }
+ };
+}
+
+impl_read_dir_from_path!(PathBuf);
+impl_read_dir_from_path!(Box);
+impl_read_dir_from_path!(Cow<'_, Path>);
+impl_read_dir_from_path!(OsString);
+impl_read_dir_from_path!(String);
+
impl fmt::Debug for ReadDir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs
index 8135519317a02..c4f3bd5f4f19d 100644
--- a/library/std/src/sys/fs/uefi.rs
+++ b/library/std/src/sys/fs/uefi.rs
@@ -415,9 +415,8 @@ impl fmt::Debug for File {
}
}
-pub fn readdir(p: &Path) -> io::Result {
- let path = crate::path::absolute(p)?;
- let f = uefi_fs::File::from_path(&path, file::MODE_READ, 0)?;
+pub fn readdir>(p: P) -> io::Result {
+ let f = uefi_fs::File::from_path(p.as_ref(), file::MODE_READ, 0)?;
let file_info = f.file_info()?;
let file_attr = FileAttr::from_uefi(file_info);
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index 9b0ef5539d32b..5ccd2325c7dab 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -6,6 +6,7 @@
#[cfg(test)]
mod tests;
+use alloc_crate::borrow::Cow;
#[cfg(all(target_os = "linux", target_env = "gnu"))]
use libc::c_char;
#[cfg(any(
@@ -272,6 +273,37 @@ impl ReadDir {
}
}
+/// Specialization trait used to construct a `ReadDir`
+trait ReadDirFromPath {
+ fn from_path(dirp: DirStream, path: P) -> Self;
+}
+
+impl> ReadDirFromPath for ReadDir {
+ default fn from_path(dirp: DirStream, path: P) -> Self {
+ let inner = InnerReadDir { dirp, root: path.as_ref().to_path_buf() };
+ ReadDir::new(inner)
+ }
+}
+
+/// This constructs a `ReadDir` for all types that can be converted
+/// into `PathBuf` without allocating
+macro_rules! impl_read_dir_from_path {
+ ($t:ty) => {
+ impl ReadDirFromPath<$t> for ReadDir {
+ fn from_path(dirp: DirStream, path: $t) -> Self {
+ let inner = InnerReadDir { dirp, root: path.into() };
+ ReadDir::new(inner)
+ }
+ }
+ };
+}
+
+impl_read_dir_from_path!(PathBuf);
+impl_read_dir_from_path!(Box);
+impl_read_dir_from_path!(Cow<'_, Path>);
+impl_read_dir_from_path!(OsString);
+impl_read_dir_from_path!(String);
+
struct DirStream(*mut libc::DIR);
// dir::Dir requires openat support
@@ -2077,14 +2109,12 @@ impl fmt::Debug for Mode {
}
}
-pub fn readdir(path: &Path) -> io::Result {
- let ptr = run_path_with_cstr(path, &|p| unsafe { Ok(libc::opendir(p.as_ptr())) })?;
+pub fn readdir>(path: P) -> io::Result {
+ let ptr = run_path_with_cstr(path.as_ref(), &|p| unsafe { Ok(libc::opendir(p.as_ptr())) })?;
if ptr.is_null() {
Err(Error::last_os_error())
} else {
- let root = path.to_path_buf();
- let inner = InnerReadDir { dirp: DirStream(ptr), root };
- Ok(ReadDir::new(inner))
+ Ok(>::from_path(DirStream(ptr), path))
}
}
diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs
index 069b4fb8a29ce..b25446b007e9f 100644
--- a/library/std/src/sys/fs/unsupported.rs
+++ b/library/std/src/sys/fs/unsupported.rs
@@ -297,7 +297,7 @@ impl fmt::Debug for File {
}
}
-pub fn readdir(_p: &Path) -> io::Result {
+pub fn readdir>(_p: P) -> io::Result {
unsupported()
}
diff --git a/library/std/src/sys/fs/vexos.rs b/library/std/src/sys/fs/vexos.rs
index 5f75bcd92421b..73d9f88de6ba1 100644
--- a/library/std/src/sys/fs/vexos.rs
+++ b/library/std/src/sys/fs/vexos.rs
@@ -477,7 +477,7 @@ impl Drop for File {
}
}
-pub fn readdir(_p: &Path) -> io::Result {
+pub fn readdir>(_p: P) -> io::Result {
// While there *is* a userspace function for reading file directories,
// the necessary implementation cannot currently be done cleanly, as
// VEXos does not expose directory length to user programs.
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index 74854cdeb498d..112e4c84e74c5 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -53,6 +53,47 @@ pub struct ReadDir {
first: Option,
}
+/// Specialization trait used to construct a `ReadDir`
+trait ReadDirFromPath {
+ fn from_path(
+ handle: Option,
+ path: P,
+ first: Option,
+ ) -> Self;
+}
+
+impl> ReadDirFromPath for ReadDir {
+ default fn from_path(
+ handle: Option,
+ path: P,
+ first: Option,
+ ) -> Self {
+ ReadDir { handle, root: Arc::new(path.as_ref().to_path_buf()), first }
+ }
+}
+
+/// This constructs a `ReadDir` for all types that can be converted
+/// into `PathBuf` without allocating
+macro_rules! impl_read_dir_from_path {
+ ($t:ty) => {
+ impl ReadDirFromPath<$t> for ReadDir {
+ fn from_path(
+ handle: Option,
+ path: $t,
+ first: Option,
+ ) -> Self {
+ ReadDir { handle, root: Arc::new(path.into()), first }
+ }
+ }
+ };
+}
+
+impl_read_dir_from_path!(PathBuf);
+impl_read_dir_from_path!(Box);
+impl_read_dir_from_path!(Cow<'_, Path>);
+impl_read_dir_from_path!(OsString);
+impl_read_dir_from_path!(String);
+
struct FindNextFileHandle(c::HANDLE);
unsafe impl Send for FindNextFileHandle {}
@@ -1222,17 +1263,16 @@ impl DirBuilder {
}
}
-pub fn readdir(p: &Path) -> io::Result {
+pub fn readdir>(p: P) -> io::Result {
// We push a `*` to the end of the path which cause the empty path to be
// treated as the current directory. So, for consistency with other platforms,
// we explicitly error on the empty path.
- if p.as_os_str().is_empty() {
+ if p.as_ref().as_os_str().is_empty() {
// Return an error code consistent with other ways of opening files.
// E.g. fs::metadata or File::open.
return Err(io::Error::from_raw_os_error(c::ERROR_PATH_NOT_FOUND as i32));
}
- let root = p.to_path_buf();
- let star = p.join("*");
+ let star = p.as_ref().join("*");
let path = maybe_verbatim(&star)?;
unsafe {
@@ -1254,11 +1294,11 @@ pub fn readdir(p: &Path) -> io::Result {
);
if find_handle != c::INVALID_HANDLE_VALUE {
- Ok(ReadDir {
- handle: Some(FindNextFileHandle(find_handle)),
- root: Arc::new(root),
- first: Some(wfd),
- })
+ Ok(>::from_path(
+ Some(FindNextFileHandle(find_handle)),
+ p,
+ Some(wfd),
+ ))
} else {
// The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileExW` function
// if no matching files can be found, but not necessarily that the path to find the
@@ -1273,7 +1313,7 @@ pub fn readdir(p: &Path) -> io::Result {
// See issue #120040: https://github.com/rust-lang/rust/issues/120040.
let last_error = api::get_last_error();
if last_error == WinError::FILE_NOT_FOUND {
- return Ok(ReadDir { handle: None, root: Arc::new(root), first: None });
+ return Ok(>::from_path(None, p, None));
}
// Just return the error constructed from the raw OS error if the above is not the case.