about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <jtitor@2k36.org>2021-07-06 02:33:06 +0900
committerGitHub <noreply@github.com>2021-07-06 02:33:06 +0900
commit1fcd9abbb1f80a0a467d8e54b573a7ba207925c7 (patch)
tree89e8ebe5d149d3aea346fa9710a1b87274cb1919
parent6e9b3696d494a32d493585f96f0671123066cd58 (diff)
parent469f4674fbed038c9d7675f1ae08354a6175b8e9 (diff)
downloadrust-1fcd9abbb1f80a0a467d8e54b573a7ba207925c7.tar.gz
rust-1fcd9abbb1f80a0a467d8e54b573a7ba207925c7.zip
Rollup merge of #83581 - arennow:dir_entry_ext_unix_borrow_name, r=m-ou-se
Add std::os::unix::fs::DirEntryExt2::file_name_ref(&self) -> &OsStr

Greetings!

This is my first PR here, so please forgive me if I've missed an important step or otherwise done something wrong. I'm very open to suggestions/fixes/corrections.

This PR adds a function that allows `std::fs::DirEntry` to vend a borrow of its filename on Unix platforms, which is especially useful for sorting. (Windows has (as I understand it) encoding differences that require an allocation.) This new function sits alongside the cross-platform [`file_name(&self) -> OsString`](https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name) function.

I pitched this idea in an [internals thread](https://internals.rust-lang.org/t/allow-std-direntry-to-vend-borrows-of-its-filename/14328/4), and no one objected vehemently, so here we are.

I understand features in general, I believe, but I'm not at all confident that my whole-cloth invention of a new feature string (as required by the compiler) was correct (or that the name is appropriate). Further, there doesn't appear to be a test for the sibling `ino` function, so I didn't add one for this similarly trivial function either. If it's desirable that I should do so, I'd be happy to [figure out how to] do that.

The following is a trivial sample of a use-case for this function, in which directory entries are sorted without any additional allocations:

```rust
use std::os::unix::fs::DirEntryExt;
use std::{fs, io};

fn main() -> io::Result<()> {
    let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
    entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));

    for p in entries {
        println!("{:?}", p);
    }

    Ok(())
}
```
-rw-r--r--library/std/src/os/unix/fs.rs39
-rw-r--r--library/std/src/sys/unix/fs.rs4
2 files changed, 43 insertions, 0 deletions
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 913c71d4108..e4ce788f741 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -9,6 +9,8 @@ use crate::path::Path;
 use crate::sys;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
 // Used for `File::read` on intra-doc links
+use crate::ffi::OsStr;
+use crate::sealed::Sealed;
 #[allow(unused_imports)]
 use io::{Read, Write};
 
@@ -839,6 +841,43 @@ impl DirEntryExt for fs::DirEntry {
     }
 }
 
+/// Sealed Unix-specific extension methods for [`fs::DirEntry`].
+#[unstable(feature = "dir_entry_ext2", issue = "85573")]
+pub trait DirEntryExt2: Sealed {
+    /// Returns a reference to the underlying `OsStr` of this entry's filename.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(dir_entry_ext2)]
+    /// use std::os::unix::fs::DirEntryExt2;
+    /// use std::{fs, io};
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
+    ///     entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
+    ///
+    ///     for p in entries {
+    ///         println!("{:?}", p);
+    ///     }
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    fn file_name_ref(&self) -> &OsStr;
+}
+
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl Sealed for fs::DirEntry {}
+
+#[unstable(feature = "dir_entry_ext2", issue = "85573")]
+impl DirEntryExt2 for fs::DirEntry {
+    fn file_name_ref(&self) -> &OsStr {
+        self.as_inner().file_name_os_str()
+    }
+}
+
 /// Creates a new symbolic link on the filesystem.
 ///
 /// The `link` path will be a symbolic link pointing to the `original` path.
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index a428ce94c8e..bec0d5898ac 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -647,6 +647,10 @@ impl DirEntry {
     fn name_bytes(&self) -> &[u8] {
         &*self.name
     }
+
+    pub fn file_name_os_str(&self) -> &OsStr {
+        OsStr::from_bytes(self.name_bytes())
+    }
 }
 
 impl OpenOptions {