Path : `CurDir` component in the middle of a path is ignored / ends_with misbehaviour?

I'm trying to compare two paths with ends_with. I was expecting the two paths in the code below to return true.

let full = PathBuf::from("/foo/goo/./blah/bloo.json");
let child = PathBuf::from("./blah/bloo.json");
  
assert!(full.ends_with(&child)); // FAIL !

ends_with is based on components which ignore CurDir (the dot) when in the middle of the path.

full = RootDir, Normal("foo"), Normal("goo"), Normal("blah"), Normal("bloo.json"), 
child = CurDir, Normal("blah"), Normal("bloo.json"), 

Is this an expected behavior? How can I work around this?

playground

I suspect it's expected behaviour, as paths are actually trickier that you expect, so doing it "right" takes being very clear about what you're trying to do.

To work around it, you could try recreating the child PathBuf by taking the components and skipping the first element (the CurDir).

let child = child.components().skip(1).collect::<PathBuf>();

or maybe use .filter(|c| !matches!(c, Component::CurDir)) if you're not sure if your child actually starts with ./. though then you check all the other parts unnecessarily, so maybe a check to see if the first element in components() is Component::CurDir, then use the skip if so.

The thing is, these two path suffixes do not mean the same thing.

The . in the first path is part of an absolute path. It's known that /foo/goo/. is unconditionally the same as /foo/goo. On the other hand, the second path is relative as it begins with the current directory – whatever it may be (eg. /bar/baz).

So no, the second path is not a suffix of the first obe, and the observed behavior is correct.

3 Likes

Ok, it makes sense. I wasn't thinking like this.

I fixed my problem by using canonicalize, since it turns all paths into absolute paths.

Keep in mind that will also fail for non-existent paths and will follow symlinks: std::env::current_dir()?.join(child) is a more conservative (and faster) equivalent, but it depends on what you're after.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.