Rollup merge of #123600 - tisonkun:path_with_extension, r=dtolnay
impl PathBuf::add_extension and Path::with_added_extension See the ACP for motivation and discussions - https://github.com/rust-lang/libs-team/issues/368
This commit is contained in:
commit
f20307851e
2 changed files with 168 additions and 0 deletions
|
@ -1519,6 +1519,74 @@ impl PathBuf {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Append [`self.extension`] with `extension`.
|
||||||
|
///
|
||||||
|
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
|
||||||
|
/// returns `true` and updates the extension otherwise.
|
||||||
|
///
|
||||||
|
/// # Caveats
|
||||||
|
///
|
||||||
|
/// The appended `extension` may contain dots and will be used in its entirety,
|
||||||
|
/// but only the part after the final dot will be reflected in
|
||||||
|
/// [`self.extension`].
|
||||||
|
///
|
||||||
|
/// See the examples below.
|
||||||
|
///
|
||||||
|
/// [`self.file_name`]: Path::file_name
|
||||||
|
/// [`self.extension`]: Path::extension
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(path_add_extension)]
|
||||||
|
///
|
||||||
|
/// use std::path::{Path, PathBuf};
|
||||||
|
///
|
||||||
|
/// let mut p = PathBuf::from("/feel/the");
|
||||||
|
///
|
||||||
|
/// p.add_extension("formatted");
|
||||||
|
/// assert_eq!(Path::new("/feel/the.formatted"), p.as_path());
|
||||||
|
///
|
||||||
|
/// p.add_extension("dark.side");
|
||||||
|
/// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path());
|
||||||
|
///
|
||||||
|
/// p.set_extension("cookie");
|
||||||
|
/// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path());
|
||||||
|
///
|
||||||
|
/// p.set_extension("");
|
||||||
|
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
|
||||||
|
///
|
||||||
|
/// p.add_extension("");
|
||||||
|
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "path_add_extension", issue = "127292")]
|
||||||
|
pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
|
||||||
|
self._add_extension(extension.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _add_extension(&mut self, extension: &OsStr) -> bool {
|
||||||
|
let file_name = match self.file_name() {
|
||||||
|
None => return false,
|
||||||
|
Some(f) => f.as_encoded_bytes(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let new = extension;
|
||||||
|
if !new.is_empty() {
|
||||||
|
// truncate until right after the file name
|
||||||
|
// this is necessary for trimming the trailing slash
|
||||||
|
let end_file_name = file_name[file_name.len()..].as_ptr().addr();
|
||||||
|
let start = self.inner.as_encoded_bytes().as_ptr().addr();
|
||||||
|
self.inner.truncate(end_file_name.wrapping_sub(start));
|
||||||
|
|
||||||
|
// append the new extension
|
||||||
|
self.inner.reserve_exact(new.len() + 1);
|
||||||
|
self.inner.push(OsStr::new("."));
|
||||||
|
self.inner.push(new);
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
/// Yields a mutable reference to the underlying [`OsString`] instance.
|
/// Yields a mutable reference to the underlying [`OsString`] instance.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -2656,6 +2724,32 @@ impl Path {
|
||||||
new_path
|
new_path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an owned [`PathBuf`] like `self` but with the extension added.
|
||||||
|
///
|
||||||
|
/// See [`PathBuf::add_extension`] for more details.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(path_add_extension)]
|
||||||
|
///
|
||||||
|
/// use std::path::{Path, PathBuf};
|
||||||
|
///
|
||||||
|
/// let path = Path::new("foo.rs");
|
||||||
|
/// assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt"));
|
||||||
|
///
|
||||||
|
/// let path = Path::new("foo.tar.gz");
|
||||||
|
/// assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz"));
|
||||||
|
/// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz"));
|
||||||
|
/// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "path_add_extension", issue = "127292")]
|
||||||
|
pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
|
||||||
|
let mut new_path = self.to_path_buf();
|
||||||
|
new_path.add_extension(extension);
|
||||||
|
new_path
|
||||||
|
}
|
||||||
|
|
||||||
/// Produces an iterator over the [`Component`]s of the path.
|
/// Produces an iterator over the [`Component`]s of the path.
|
||||||
///
|
///
|
||||||
/// When parsing the path, there is a small amount of normalization:
|
/// When parsing the path, there is a small amount of normalization:
|
||||||
|
|
|
@ -1401,6 +1401,37 @@ pub fn test_set_extension() {
|
||||||
tfe!("/", "foo", "/", false);
|
tfe!("/", "foo", "/", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_add_extension() {
|
||||||
|
macro_rules! tfe (
|
||||||
|
($path:expr, $ext:expr, $expected:expr, $output:expr) => ({
|
||||||
|
let mut p = PathBuf::from($path);
|
||||||
|
let output = p.add_extension($ext);
|
||||||
|
assert!(p.to_str() == Some($expected) && output == $output,
|
||||||
|
"adding extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
|
||||||
|
$path, $ext, $expected, $output,
|
||||||
|
p.to_str().unwrap(), output);
|
||||||
|
});
|
||||||
|
);
|
||||||
|
|
||||||
|
tfe!("foo", "txt", "foo.txt", true);
|
||||||
|
tfe!("foo.bar", "txt", "foo.bar.txt", true);
|
||||||
|
tfe!("foo.bar.baz", "txt", "foo.bar.baz.txt", true);
|
||||||
|
tfe!(".test", "txt", ".test.txt", true);
|
||||||
|
tfe!("foo.txt", "", "foo.txt", true);
|
||||||
|
tfe!("foo", "", "foo", true);
|
||||||
|
tfe!("", "foo", "", false);
|
||||||
|
tfe!(".", "foo", ".", false);
|
||||||
|
tfe!("foo/", "bar", "foo.bar", true);
|
||||||
|
tfe!("foo/.", "bar", "foo.bar", true);
|
||||||
|
tfe!("..", "foo", "..", false);
|
||||||
|
tfe!("foo/..", "bar", "foo/..", false);
|
||||||
|
tfe!("/", "foo", "/", false);
|
||||||
|
|
||||||
|
// edge cases
|
||||||
|
tfe!("/foo.ext////", "bar", "/foo.ext.bar", true);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_with_extension() {
|
pub fn test_with_extension() {
|
||||||
macro_rules! twe (
|
macro_rules! twe (
|
||||||
|
@ -1441,6 +1472,49 @@ pub fn test_with_extension() {
|
||||||
twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.aaa_aaa_aaa");
|
twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.aaa_aaa_aaa");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_with_added_extension() {
|
||||||
|
macro_rules! twe (
|
||||||
|
($input:expr, $extension:expr, $expected:expr) => ({
|
||||||
|
let input = Path::new($input);
|
||||||
|
let output = input.with_added_extension($extension);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.to_str() == Some($expected),
|
||||||
|
"calling Path::new({:?}).with_added_extension({:?}): Expected {:?}, got {:?}",
|
||||||
|
$input, $extension, $expected, output,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
);
|
||||||
|
|
||||||
|
twe!("foo", "txt", "foo.txt");
|
||||||
|
twe!("foo.bar", "txt", "foo.bar.txt");
|
||||||
|
twe!("foo.bar.baz", "txt", "foo.bar.baz.txt");
|
||||||
|
twe!(".test", "txt", ".test.txt");
|
||||||
|
twe!("foo.txt", "", "foo.txt");
|
||||||
|
twe!("foo", "", "foo");
|
||||||
|
twe!("", "foo", "");
|
||||||
|
twe!(".", "foo", ".");
|
||||||
|
twe!("foo/", "bar", "foo.bar");
|
||||||
|
twe!("foo/.", "bar", "foo.bar");
|
||||||
|
twe!("..", "foo", "..");
|
||||||
|
twe!("foo/..", "bar", "foo/..");
|
||||||
|
twe!("/", "foo", "/");
|
||||||
|
|
||||||
|
// edge cases
|
||||||
|
twe!("/foo.ext////", "bar", "/foo.ext.bar");
|
||||||
|
|
||||||
|
// New extension is smaller than file name
|
||||||
|
twe!("aaa_aaa_aaa", "bbb_bbb", "aaa_aaa_aaa.bbb_bbb");
|
||||||
|
// New extension is greater than file name
|
||||||
|
twe!("bbb_bbb", "aaa_aaa_aaa", "bbb_bbb.aaa_aaa_aaa");
|
||||||
|
|
||||||
|
// New extension is smaller than previous extension
|
||||||
|
twe!("ccc.aaa_aaa_aaa", "bbb_bbb", "ccc.aaa_aaa_aaa.bbb_bbb");
|
||||||
|
// New extension is greater than previous extension
|
||||||
|
twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.bbb_bbb.aaa_aaa_aaa");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eq_receivers() {
|
fn test_eq_receivers() {
|
||||||
use crate::borrow::Cow;
|
use crate::borrow::Cow;
|
||||||
|
|
Loading…
Add table
Reference in a new issue