Skip to content

Commit 4a2eeae

Browse files
committed
Add PathLike trait
Replace `AsRef<Path>` with a `PathLike` trait.
1 parent 31f858d commit 4a2eeae

File tree

9 files changed

+190
-62
lines changed

9 files changed

+190
-62
lines changed

library/std/src/env.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use crate::error::Error;
1717
use crate::ffi::{OsStr, OsString};
1818
use crate::fmt;
1919
use crate::io;
20-
use crate::path::{Path, PathBuf};
20+
#[cfg(doc)]
21+
use crate::path::Path;
22+
use crate::path::{PathBuf, PathLike};
2123
use crate::sys;
2224
use crate::sys::os as os_imp;
2325

@@ -80,8 +82,8 @@ pub fn current_dir() -> io::Result<PathBuf> {
8082
/// ```
8183
#[doc(alias = "chdir")]
8284
#[stable(feature = "env", since = "1.0.0")]
83-
pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
84-
os_imp::chdir(path.as_ref())
85+
pub fn set_current_dir<P: PathLike>(path: P) -> io::Result<()> {
86+
path.with_path(os_imp::chdir)
8587
}
8688

8789
/// An iterator over a snapshot of the environment variables of this process.

library/std/src/fs.rs

+51-51
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod tests;
1414
use crate::ffi::OsString;
1515
use crate::fmt;
1616
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
17-
use crate::path::{Path, PathBuf};
17+
use crate::path::{NativePath, Path, PathBuf, PathLike};
1818
use crate::sys::fs as fs_imp;
1919
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
2020
use crate::time::SystemTime;
@@ -246,15 +246,15 @@ pub struct DirBuilder {
246246
/// }
247247
/// ```
248248
#[stable(feature = "fs_read_write_bytes", since = "1.26.0")]
249-
pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
249+
pub fn read<P: PathLike>(path: P) -> io::Result<Vec<u8>> {
250250
fn inner(path: &Path) -> io::Result<Vec<u8>> {
251251
let mut file = File::open(path)?;
252252
let size = file.metadata().map(|m| m.len()).unwrap_or(0);
253253
let mut bytes = Vec::with_capacity(size as usize);
254254
io::default_read_to_end(&mut file, &mut bytes)?;
255255
Ok(bytes)
256256
}
257-
inner(path.as_ref())
257+
path.with_path(inner)
258258
}
259259

260260
/// Read the entire contents of a file into a string.
@@ -286,15 +286,15 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
286286
/// }
287287
/// ```
288288
#[stable(feature = "fs_read_write", since = "1.26.0")]
289-
pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
289+
pub fn read_to_string<P: PathLike>(path: P) -> io::Result<String> {
290290
fn inner(path: &Path) -> io::Result<String> {
291291
let mut file = File::open(path)?;
292292
let size = file.metadata().map(|m| m.len()).unwrap_or(0);
293293
let mut string = String::with_capacity(size as usize);
294294
io::default_read_to_string(&mut file, &mut string)?;
295295
Ok(string)
296296
}
297-
inner(path.as_ref())
297+
path.with_path(inner)
298298
}
299299

300300
/// Write a slice as the entire contents of a file.
@@ -322,11 +322,11 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
322322
/// }
323323
/// ```
324324
#[stable(feature = "fs_read_write_bytes", since = "1.26.0")]
325-
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
325+
pub fn write<P: PathLike, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
326326
fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
327327
File::create(path)?.write_all(contents)
328328
}
329-
inner(path.as_ref(), contents.as_ref())
329+
path.with_path(|path| inner(path.as_ref(), contents.as_ref()))
330330
}
331331

332332
impl File {
@@ -357,8 +357,8 @@ impl File {
357357
/// }
358358
/// ```
359359
#[stable(feature = "rust1", since = "1.0.0")]
360-
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
361-
OpenOptions::new().read(true).open(path.as_ref())
360+
pub fn open<P: PathLike>(path: P) -> io::Result<File> {
361+
OpenOptions::new().read(true).open(path)
362362
}
363363

364364
/// Opens a file in write-only mode.
@@ -386,8 +386,8 @@ impl File {
386386
/// }
387387
/// ```
388388
#[stable(feature = "rust1", since = "1.0.0")]
389-
pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
390-
OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
389+
pub fn create<P: PathLike>(path: P) -> io::Result<File> {
390+
OpenOptions::new().write(true).create(true).truncate(true).open(path)
391391
}
392392

393393
/// Creates a new file in read-write mode; error if the file exists.
@@ -417,8 +417,8 @@ impl File {
417417
/// }
418418
/// ```
419419
#[unstable(feature = "file_create_new", issue = "105135")]
420-
pub fn create_new<P: AsRef<Path>>(path: P) -> io::Result<File> {
421-
OpenOptions::new().read(true).write(true).create_new(true).open(path.as_ref())
420+
pub fn create_new<P: PathLike>(path: P) -> io::Result<File> {
421+
OpenOptions::new().read(true).write(true).create_new(true).open(path)
422422
}
423423

424424
/// Returns a new OpenOptions object.
@@ -1073,12 +1073,12 @@ impl OpenOptions {
10731073
/// [`NotFound`]: io::ErrorKind::NotFound
10741074
/// [`PermissionDenied`]: io::ErrorKind::PermissionDenied
10751075
#[stable(feature = "rust1", since = "1.0.0")]
1076-
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
1077-
self._open(path.as_ref())
1076+
pub fn open<P: PathLike>(&self, path: P) -> io::Result<File> {
1077+
path.with_native_path(|path| self._open(path))
10781078
}
10791079

1080-
fn _open(&self, path: &Path) -> io::Result<File> {
1081-
fs_imp::File::open(path, &self.0).map(|inner| File { inner })
1080+
fn _open(&self, path: &NativePath) -> io::Result<File> {
1081+
fs_imp::File::open_native(path, &self.0).map(|inner| File { inner })
10821082
}
10831083
}
10841084

@@ -1805,8 +1805,8 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
18051805
/// }
18061806
/// ```
18071807
#[stable(feature = "rust1", since = "1.0.0")]
1808-
pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
1809-
fs_imp::unlink(path.as_ref())
1808+
pub fn remove_file<P: PathLike>(path: P) -> io::Result<()> {
1809+
path.with_path(fs_imp::unlink)
18101810
}
18111811

18121812
/// Given a path, query the file system to get information about a file,
@@ -1843,8 +1843,8 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
18431843
/// }
18441844
/// ```
18451845
#[stable(feature = "rust1", since = "1.0.0")]
1846-
pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
1847-
fs_imp::stat(path.as_ref()).map(Metadata)
1846+
pub fn metadata<P: PathLike>(path: P) -> io::Result<Metadata> {
1847+
path.with_path(fs_imp::stat).map(Metadata)
18481848
}
18491849

18501850
/// Query the metadata about a file without following symlinks.
@@ -1877,8 +1877,8 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
18771877
/// }
18781878
/// ```
18791879
#[stable(feature = "symlink_metadata", since = "1.1.0")]
1880-
pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
1881-
fs_imp::lstat(path.as_ref()).map(Metadata)
1880+
pub fn symlink_metadata<P: PathLike>(path: P) -> io::Result<Metadata> {
1881+
path.with_path(fs_imp::lstat).map(Metadata)
18821882
}
18831883

18841884
/// Rename a file or directory to a new name, replacing the original file if
@@ -1920,8 +1920,8 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
19201920
/// }
19211921
/// ```
19221922
#[stable(feature = "rust1", since = "1.0.0")]
1923-
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
1924-
fs_imp::rename(from.as_ref(), to.as_ref())
1923+
pub fn rename<P: PathLike, Q: PathLike>(from: P, to: Q) -> io::Result<()> {
1924+
from.with_path(|from| to.with_path(|to| fs_imp::rename(from, to)))
19251925
}
19261926

19271927
/// Copies the contents of one file to another. This function will also
@@ -1978,8 +1978,8 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
19781978
/// }
19791979
/// ```
19801980
#[stable(feature = "rust1", since = "1.0.0")]
1981-
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
1982-
fs_imp::copy(from.as_ref(), to.as_ref())
1981+
pub fn copy<P: PathLike, Q: PathLike>(from: P, to: Q) -> io::Result<u64> {
1982+
from.with_path(|from| to.with_path(|to| fs_imp::copy(from, to)))
19831983
}
19841984

19851985
/// Creates a new hard link on the filesystem.
@@ -2022,8 +2022,8 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
20222022
/// }
20232023
/// ```
20242024
#[stable(feature = "rust1", since = "1.0.0")]
2025-
pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
2026-
fs_imp::link(original.as_ref(), link.as_ref())
2025+
pub fn hard_link<P: PathLike, Q: PathLike>(original: P, link: Q) -> io::Result<()> {
2026+
original.with_path(|original| link.with_path(|link| fs_imp::link(original, link)))
20272027
}
20282028

20292029
/// Creates a new symbolic link on the filesystem.
@@ -2054,8 +2054,8 @@ pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Re
20542054
note = "replaced with std::os::unix::fs::symlink and \
20552055
std::os::windows::fs::{symlink_file, symlink_dir}"
20562056
)]
2057-
pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
2058-
fs_imp::symlink(original.as_ref(), link.as_ref())
2057+
pub fn soft_link<P: PathLike, Q: PathLike>(original: P, link: Q) -> io::Result<()> {
2058+
original.with_path(|original| link.with_path(|link| fs_imp::symlink(original, link)))
20592059
}
20602060

20612061
/// Reads a symbolic link, returning the file that the link points to.
@@ -2088,8 +2088,8 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Re
20882088
/// }
20892089
/// ```
20902090
#[stable(feature = "rust1", since = "1.0.0")]
2091-
pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
2092-
fs_imp::readlink(path.as_ref())
2091+
pub fn read_link<P: PathLike>(path: P) -> io::Result<PathBuf> {
2092+
path.with_path(fs_imp::readlink)
20932093
}
20942094

20952095
/// Returns the canonical, absolute form of a path with all intermediate
@@ -2131,8 +2131,8 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
21312131
#[doc(alias = "realpath")]
21322132
#[doc(alias = "GetFinalPathNameByHandle")]
21332133
#[stable(feature = "fs_canonicalize", since = "1.5.0")]
2134-
pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
2135-
fs_imp::canonicalize(path.as_ref())
2134+
pub fn canonicalize<P: PathLike>(path: P) -> io::Result<PathBuf> {
2135+
path.with_path(fs_imp::canonicalize)
21362136
}
21372137

21382138
/// Creates a new, empty directory at the provided path
@@ -2172,8 +2172,8 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
21722172
/// ```
21732173
#[doc(alias = "mkdir")]
21742174
#[stable(feature = "rust1", since = "1.0.0")]
2175-
pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
2176-
DirBuilder::new().create(path.as_ref())
2175+
pub fn create_dir<P: PathLike>(path: P) -> io::Result<()> {
2176+
DirBuilder::new().create(path)
21772177
}
21782178

21792179
/// Recursively create a directory and all of its parent components if they
@@ -2216,8 +2216,8 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
22162216
/// }
22172217
/// ```
22182218
#[stable(feature = "rust1", since = "1.0.0")]
2219-
pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
2220-
DirBuilder::new().recursive(true).create(path.as_ref())
2219+
pub fn create_dir_all<P: PathLike>(path: P) -> io::Result<()> {
2220+
DirBuilder::new().recursive(true).create(path)
22212221
}
22222222

22232223
/// Removes an empty directory.
@@ -2252,8 +2252,8 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
22522252
/// ```
22532253
#[doc(alias = "rmdir")]
22542254
#[stable(feature = "rust1", since = "1.0.0")]
2255-
pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
2256-
fs_imp::rmdir(path.as_ref())
2255+
pub fn remove_dir<P: PathLike>(path: P) -> io::Result<()> {
2256+
path.with_path(fs_imp::rmdir)
22572257
}
22582258

22592259
/// Removes a directory at this path, after removing all its contents. Use
@@ -2294,8 +2294,8 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
22942294
/// }
22952295
/// ```
22962296
#[stable(feature = "rust1", since = "1.0.0")]
2297-
pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
2298-
fs_imp::remove_dir_all(path.as_ref())
2297+
pub fn remove_dir_all<P: PathLike>(path: P) -> io::Result<()> {
2298+
path.with_path(fs_imp::remove_dir_all)
22992299
}
23002300

23012301
/// Returns an iterator over the entries within a directory.
@@ -2369,8 +2369,8 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
23692369
/// }
23702370
/// ```
23712371
#[stable(feature = "rust1", since = "1.0.0")]
2372-
pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
2373-
fs_imp::readdir(path.as_ref()).map(ReadDir)
2372+
pub fn read_dir<P: PathLike>(path: P) -> io::Result<ReadDir> {
2373+
path.with_path(fs_imp::readdir).map(ReadDir)
23742374
}
23752375

23762376
/// Changes the permissions found on a file or a directory.
@@ -2404,8 +2404,8 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
24042404
/// }
24052405
/// ```
24062406
#[stable(feature = "set_permissions", since = "1.1.0")]
2407-
pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
2408-
fs_imp::set_perm(path.as_ref(), perm.0)
2407+
pub fn set_permissions<P: PathLike>(path: P, perm: Permissions) -> io::Result<()> {
2408+
path.with_path(|path| fs_imp::set_perm(path, perm.0))
24092409
}
24102410

24112411
impl DirBuilder {
@@ -2464,8 +2464,8 @@ impl DirBuilder {
24642464
/// assert!(fs::metadata(path).unwrap().is_dir());
24652465
/// ```
24662466
#[stable(feature = "dir_builder", since = "1.6.0")]
2467-
pub fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
2468-
self._create(path.as_ref())
2467+
pub fn create<P: PathLike>(&self, path: P) -> io::Result<()> {
2468+
path.with_path(|path| self._create(path))
24692469
}
24702470

24712471
fn _create(&self, path: &Path) -> io::Result<()> {
@@ -2534,6 +2534,6 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
25342534
// instead.
25352535
#[unstable(feature = "fs_try_exists", issue = "83186")]
25362536
#[inline]
2537-
pub fn try_exists<P: AsRef<Path>>(path: P) -> io::Result<bool> {
2538-
fs_imp::try_exists(path.as_ref())
2537+
pub fn try_exists<P: PathLike>(path: P) -> io::Result<bool> {
2538+
path.with_path(fs_imp::try_exists)
25392539
}

library/std/src/os/unix/ffi/mod.rs

+19
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,24 @@
3838

3939
mod os_str;
4040

41+
use crate::ffi::CStr;
42+
use crate::path::NativePath;
43+
4144
#[stable(feature = "rust1", since = "1.0.0")]
4245
pub use self::os_str::{OsStrExt, OsStringExt};
46+
47+
#[unstable(feature = "pathlike", issue = "none")]
48+
pub trait NativePathExt: crate::sealed::Sealed {
49+
fn from_cstr(cstr: &CStr) -> &NativePath;
50+
fn into_cstr(&self) -> &CStr;
51+
}
52+
53+
#[unstable(feature = "pathlike", issue = "none")]
54+
impl NativePathExt for NativePath {
55+
fn from_cstr(cstr: &CStr) -> &NativePath {
56+
unsafe { &*(cstr as *const CStr as *const NativePath) }
57+
}
58+
fn into_cstr(&self) -> &CStr {
59+
unsafe { &*(self as *const Self as *const CStr) }
60+
}
61+
}

library/std/src/os/windows/ffi.rs

+17
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#![stable(feature = "rust1", since = "1.0.0")]
5555

5656
use crate::ffi::{OsStr, OsString};
57+
use crate::path::NativePath;
5758
use crate::sealed::Sealed;
5859
use crate::sys::os_str::Buf;
5960
use crate::sys_common::wtf8::Wtf8Buf;
@@ -134,3 +135,19 @@ impl OsStrExt for OsStr {
134135
self.as_inner().inner.encode_wide()
135136
}
136137
}
138+
139+
#[unstable(feature = "pathlike", issue = "none")]
140+
pub trait NativePathExt: Sealed {
141+
fn from_wide(wide: &[u16]) -> &NativePath;
142+
fn into_wide(&self) -> &[u16];
143+
}
144+
#[unstable(feature = "pathlike", issue = "none")]
145+
impl NativePathExt for NativePath {
146+
fn from_wide(wide: &[u16]) -> &NativePath {
147+
assert_eq!(wide.last(), Some(&0));
148+
unsafe { &*(wide as *const [u16] as *const Self) }
149+
}
150+
fn into_wide(&self) -> &[u16] {
151+
unsafe { &*(self as *const Self as *const [u16]) }
152+
}
153+
}

0 commit comments

Comments
 (0)