From b999b7df925c1af849c2800838b201662d8e029b Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Mon, 2 Nov 2015 21:39:23 +0100 Subject: [PATCH 1/3] Make port: None equal to port: default_port Fix #132 --- src/lib.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index fb7c48bc3..03e7c59ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -137,6 +137,7 @@ use std::fmt::{self, Formatter}; use std::str; use std::path::{Path, PathBuf}; use std::borrow::Borrow; +use std::hash::{Hash, Hasher}; #[cfg(feature="serde_serialization")] use std::str::FromStr; @@ -226,7 +227,7 @@ pub enum SchemeData { } /// Components for URLs in a *relative* scheme such as HTTP. -#[derive(PartialEq, Eq, Clone, Debug, Hash, PartialOrd, Ord)] +#[derive(Clone, Debug, PartialOrd, Ord)] #[cfg_attr(feature="heap_size", derive(HeapSizeOf))] pub struct RelativeSchemeData { /// The username of the URL, as a possibly empty, percent-encoded string. @@ -266,6 +267,33 @@ pub struct RelativeSchemeData { pub path: Vec, } +impl RelativeSchemeData { + fn get_identity_key(&self) -> (&String, &Option, &Host, Option, Option, &Vec) { + ( + &self.username, + &self.password, + &self.host, + self.port.or(self.default_port), + self.default_port, + &self.path + ) + } +} + + +impl PartialEq for RelativeSchemeData { + fn eq(&self, other: &RelativeSchemeData) -> bool { + self.get_identity_key() == other.get_identity_key() + } +} + +impl Eq for RelativeSchemeData {} + +impl Hash for RelativeSchemeData { + fn hash(&self, state: &mut H) { + self.get_identity_key().hash(state) + } +} impl str::FromStr for Url { type Err = ParseError; From 3e72c195815c603b257d32ea406f9df479015eac Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Tue, 10 Nov 2015 21:05:28 +0100 Subject: [PATCH 2/3] Manually impl Ord, PartialOrd --- src/lib.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 03e7c59ca..08d32ef55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,6 +138,7 @@ use std::str; use std::path::{Path, PathBuf}; use std::borrow::Borrow; use std::hash::{Hash, Hasher}; +use std::cmp::Ordering; #[cfg(feature="serde_serialization")] use std::str::FromStr; @@ -227,7 +228,7 @@ pub enum SchemeData { } /// Components for URLs in a *relative* scheme such as HTTP. -#[derive(Clone, Debug, PartialOrd, Ord)] +#[derive(Clone, Debug)] #[cfg_attr(feature="heap_size", derive(HeapSizeOf))] pub struct RelativeSchemeData { /// The username of the URL, as a possibly empty, percent-encoded string. @@ -295,6 +296,18 @@ impl Hash for RelativeSchemeData { } } +impl PartialOrd for RelativeSchemeData { + fn partial_cmp(&self, other: &RelativeSchemeData) -> Option { + self.get_identity_key().partial_cmp(&other.get_identity_key()) + } +} + +impl Ord for RelativeSchemeData { + fn cmp(&self, other: &Self) -> Ordering { + self.get_identity_key().cmp(&other.get_identity_key()) + } +} + impl str::FromStr for Url { type Err = ParseError; From ab7f6fc0e8f77afbb48bb262176fc831ad4bb42e Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Tue, 10 Nov 2015 21:24:08 +0100 Subject: [PATCH 3/3] Add tests --- src/tests.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/tests.rs b/src/tests.rs index 146ad3a20..e25500f5c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -301,3 +301,49 @@ fn issue_124() { let url: Url = "file:..".parse().unwrap(); assert_eq!(url.path().unwrap(), [""]); } + +#[test] +fn relative_scheme_data_equality() { + use std::hash::{Hash, Hasher, SipHasher}; + + fn check_eq(a: &Url, b: &Url) { + assert_eq!(a, b); + + let mut h1 = SipHasher::new(); + a.hash(&mut h1); + let mut h2 = SipHasher::new(); + b.hash(&mut h2); + assert_eq!(h1.finish(), h2.finish()); + } + + fn url(s: &str) -> Url { + let rv = s.parse().unwrap(); + check_eq(&rv, &rv); + rv + } + + // Doesn't care if default port is given. + let a: Url = url("https://example.com/"); + let b: Url = url("https://example.com:443/"); + check_eq(&a, &b); + + // Different ports + let a: Url = url("http://example.com/"); + let b: Url = url("http://example.com:8080/"); + assert!(a != b); + + // Different scheme + let a: Url = url("http://example.com/"); + let b: Url = url("https://example.com/"); + assert!(a != b); + + // Different host + let a: Url = url("http://foo.com/"); + let b: Url = url("http://bar.com/"); + assert!(a != b); + + // Missing path, automatically substituted. Semantically the same. + let a: Url = url("http://foo.com"); + let b: Url = url("http://foo.com/"); + check_eq(&a, &b); +}