Description
Given:
use std::path::{Path, PathBuf};
fn main() {
let mut p = PathBuf::from("/a/b/c");
println!("{:?} {:?}", p, p.file_name());
p.push("");
println!("{:?} {:?}", p, p.file_name());
p.push("");
println!("{:?} {:?}", p, p.file_name());
p.pop();
println!("{:?} {:?}", p, p.file_name());
p = PathBuf::from("/");
println!("{:?} {:?}", p, p.file_name());
p.push("");
println!("{:?} {:?}", p, p.file_name());
p.push("");
println!("{:?} {:?}", p, p.file_name());
p.pop();
println!("{:?} {:?}", p, p.file_name());
}
You get:
"/a/b/c" Some("c")
"/a/b/c/" Some("c")
"/a/b/c/" Some("c")
"/a/b" Some("b")
"/" None
"/" None
"/" None
"/" None
First, the documentation is misleading (wrong?). file_name
(https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.file_name) is documented as "The final component of the path, if it is a normal file.", but it's returning the directory when there's a trailing slash, which is not (by my book) a normal file?
Looking at the implementation of components
it will return the final component of the path unless it is the root directory or a relative component. Maybe it just needs clarifying.
There's a stranger issue with normalisation of trailing slashes. Initially I thought it should be documented (https://doc.rust-lang.org/std/path/index.html#normalization), because trailing slashes are ignored by components()
. However, unlike any other normalisation, it is possible to reconstruct the original path (by doing .push("")
)!
I'm unsure what the intended behaviour is here and what needs fixing (implementation or docs).
Given stabilisation, I'm going to assume that implemented behaviour wins at this point? It's slightly irritating because being able to detect a trailing slash can be useful (as rsync does). Failing that I might be tempted to make .push("")
do nothing - this uncertain state with trailing slashes is strange. Is there an RFC I can look at maybe?