@@ -2719,11 +2719,30 @@ impl Path {
2719
2719
PathBuf { inner : OsString :: from ( inner) }
2720
2720
}
2721
2721
2722
- fn ends_with_separator ( & self ) -> bool {
2722
+ /// Returns true if the path's syntax indicates it necessarily can only
2723
+ /// refer to a directory.
2724
+ ///
2725
+ /// This is relevant to the PartialEq and PartialOrd impls of Path. For
2726
+ /// example, compared as paths "r/s/" and "r/s/." and "r/s/./" and "r/s/./."
2727
+ /// are all in the same equivalence class, but a different class from "r/s".
2728
+ /// That's because if "r/s" is a file then "r/s" exists while most
2729
+ /// filesystems would consider that "r/s/" does not exist, and thus these
2730
+ /// must not be equal paths.
2731
+ fn syntactically_dir ( & self ) -> bool {
2723
2732
let components = self . components ( ) ;
2724
- match components. path . last ( ) {
2725
- None => false ,
2726
- Some ( byte) => components. is_sep_byte ( * byte) ,
2733
+ let bytes_after_prefix =
2734
+ & components. path [ components. prefix . as_ref ( ) . map_or ( 0 , Prefix :: len) ..] ;
2735
+ let mut bytes_iter = bytes_after_prefix. iter ( ) ;
2736
+ let last_byte = bytes_iter. next_back ( ) ;
2737
+ let second_last_byte = bytes_iter. next_back ( ) ;
2738
+ match ( second_last_byte, last_byte) {
2739
+ // Path ends in separator, like "path/to/"
2740
+ ( _, Some ( & sep) ) if components. is_sep_byte ( sep) => true ,
2741
+ // Path ends in separator followed by CurDir, like "path/to/."
2742
+ ( Some ( & sep) , Some ( b'.' ) ) if components. is_sep_byte ( sep) => true ,
2743
+ // Path is ".", because "." and "./." need to be considered equal
2744
+ ( None , Some ( b'.' ) ) => true ,
2745
+ _ => false ,
2727
2746
}
2728
2747
}
2729
2748
}
@@ -2787,7 +2806,7 @@ impl cmp::PartialEq for Path {
2787
2806
#[ inline]
2788
2807
fn eq ( & self , other : & Path ) -> bool {
2789
2808
self . components ( ) == other. components ( )
2790
- && self . ends_with_separator ( ) == other. ends_with_separator ( )
2809
+ && self . syntactically_dir ( ) == other. syntactically_dir ( )
2791
2810
}
2792
2811
}
2793
2812
@@ -2816,7 +2835,7 @@ impl cmp::Ord for Path {
2816
2835
#[ inline]
2817
2836
fn cmp ( & self , other : & Path ) -> cmp:: Ordering {
2818
2837
compare_components ( self . components ( ) , other. components ( ) )
2819
- . then_with ( || self . ends_with_separator ( ) . cmp ( & other. ends_with_separator ( ) ) )
2838
+ . then_with ( || self . syntactically_dir ( ) . cmp ( & other. syntactically_dir ( ) ) )
2820
2839
}
2821
2840
}
2822
2841
0 commit comments