mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
std: Base Hash for Path on its iterator
Almost all operations on Path are based on the components iterator in one form or another to handle equivalent paths. The `Hash` implementations, however, mistakenly just went straight to the underlying `OsStr`, causing these equivalent paths to not get merged together. This commit updates the `Hash` implementation to also be based on the iterator which should ensure that if two paths are equal they hash to the same thing. cc #29008, but doesn't close it
This commit is contained in:
parent
01fd4d6227
commit
d2dd700891
@ -103,6 +103,7 @@ use borrow::{Borrow, IntoCow, ToOwned, Cow};
|
|||||||
use cmp;
|
use cmp;
|
||||||
use fmt;
|
use fmt;
|
||||||
use fs;
|
use fs;
|
||||||
|
use hash::{Hash, Hasher};
|
||||||
use io;
|
use io;
|
||||||
use iter;
|
use iter;
|
||||||
use mem;
|
use mem;
|
||||||
@ -446,7 +447,7 @@ enum State {
|
|||||||
///
|
///
|
||||||
/// Does not occur on Unix.
|
/// Does not occur on Unix.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Copy, Clone, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, Debug)]
|
||||||
pub struct PrefixComponent<'a> {
|
pub struct PrefixComponent<'a> {
|
||||||
/// The prefix as an unparsed `OsStr` slice.
|
/// The prefix as an unparsed `OsStr` slice.
|
||||||
raw: &'a OsStr,
|
raw: &'a OsStr,
|
||||||
@ -490,6 +491,13 @@ impl<'a> cmp::Ord for PrefixComponent<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<'a> Hash for PrefixComponent<'a> {
|
||||||
|
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||||
|
self.parsed.hash(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A single component of a path.
|
/// A single component of a path.
|
||||||
///
|
///
|
||||||
/// See the module documentation for an in-depth explanation of components and
|
/// See the module documentation for an in-depth explanation of components and
|
||||||
@ -932,7 +940,7 @@ impl<'a> cmp::Ord for Components<'a> {
|
|||||||
/// path.push("system32");
|
/// path.push("system32");
|
||||||
/// path.set_extension("dll");
|
/// path.set_extension("dll");
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct PathBuf {
|
pub struct PathBuf {
|
||||||
inner: OsString
|
inner: OsString
|
||||||
@ -1171,6 +1179,13 @@ impl cmp::PartialEq for PathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl Hash for PathBuf {
|
||||||
|
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||||
|
self.as_path().hash(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl cmp::Eq for PathBuf {}
|
impl cmp::Eq for PathBuf {}
|
||||||
|
|
||||||
@ -1224,7 +1239,6 @@ impl Into<OsString> for PathBuf {
|
|||||||
/// let parent_dir = path.parent();
|
/// let parent_dir = path.parent();
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
#[derive(Hash)]
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Path {
|
pub struct Path {
|
||||||
inner: OsStr
|
inner: OsStr
|
||||||
@ -1809,6 +1823,15 @@ impl cmp::PartialEq for Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl Hash for Path {
|
||||||
|
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||||
|
for component in self.components() {
|
||||||
|
component.hash(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl cmp::Eq for Path {}
|
impl cmp::Eq for Path {}
|
||||||
|
|
||||||
@ -3035,6 +3058,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_compare() {
|
pub fn test_compare() {
|
||||||
|
use hash::{Hash, Hasher, SipHasher};
|
||||||
|
|
||||||
|
fn hash<T: Hash>(t: T) -> u64 {
|
||||||
|
let mut s = SipHasher::new_with_keys(0, 0);
|
||||||
|
t.hash(&mut s);
|
||||||
|
s.finish()
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! tc(
|
macro_rules! tc(
|
||||||
($path1:expr, $path2:expr, eq: $eq:expr,
|
($path1:expr, $path2:expr, eq: $eq:expr,
|
||||||
starts_with: $starts_with:expr, ends_with: $ends_with:expr,
|
starts_with: $starts_with:expr, ends_with: $ends_with:expr,
|
||||||
@ -3045,6 +3076,9 @@ mod tests {
|
|||||||
let eq = path1 == path2;
|
let eq = path1 == path2;
|
||||||
assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
|
assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
|
||||||
$path1, $path2, $eq, eq);
|
$path1, $path2, $eq, eq);
|
||||||
|
assert!($eq == (hash(path1) == hash(path2)),
|
||||||
|
"{:?} == {:?}, expected {:?}, got {} and {}",
|
||||||
|
$path1, $path2, $eq, hash(path1), hash(path2));
|
||||||
|
|
||||||
let starts_with = path1.starts_with(path2);
|
let starts_with = path1.starts_with(path2);
|
||||||
assert!(starts_with == $starts_with,
|
assert!(starts_with == $starts_with,
|
||||||
|
Loading…
Reference in New Issue
Block a user