http icon indicating copy to clipboard operation
http copied to clipboard

Implement PartialOrd and Ord for http::Uri

Open Luro02 opened this issue 4 years ago • 5 comments

I thought about an implementation like this

impl PartialOrd for Uri {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Uri {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.eq(other) {
            Ordering::Equal
        } else {
            (self.scheme(), self.authority(), self.path_and_query())
                .cmp(&(other.scheme(), other.authority(), other.path_and_query()))
        }
    }
}

the problem is the components only implement PartialOrd.

Another option would be:

impl PartialOrd for Uri {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Uri {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.eq(other) {
            Ordering::Equal
        } else {
            self.to_string().cmp(other.to_string())
        }
    }
}

Luro02 avatar Mar 29 '20 18:03 Luro02

Do you have a use case in mind for this? Could you share?

dekellum avatar Dec 12 '20 17:12 dekellum

Do you have a use case in mind for this? Could you share?

Deriving the PartialOrd and Ord traits on types that contain the http::Uri type?

Luro02 avatar Dec 12 '20 20:12 Luro02

Do those types of yours suggest any particular ordering for the Uri component? What I'm (just a contributor) looking for is if there is a particularly natural ordering. For example, compared to your first suggested Ord impl, I might have chosen:

(self.authority().host(), self.authority().port(), self.scheme(), self.path_and_query())

...in that order, as being more natural.

dekellum avatar Dec 12 '20 21:12 dekellum

As far as I remember, there was no particular reason, why I proposed the above implementation. It was meant as a suggestion, how this could be implemented.

I think it does not even matter that the ordering makes sense (for my use case), because I only wanted it, so I do not have to implement PartialEq, Eq, PartialOrd, Ord and Hash manually for the structs that use http::Uri internally. (All the trait implementations have to agree with each other).

I am not very familiar with this crate, so I do not know if your ordering is more natural, but my proposal would work with crates that use http::Uri conditionally and fallback to String. (The ordering for http::Uri would be equivalent to its String equivalent)

Luro02 avatar Dec 12 '20 21:12 Luro02

Authority currently does a case-insensitive host PartialOrd which is different then ordering the output of to_string(). That might suggest this ordering is more consistent than my original suggestion:

(self.authority(), self.scheme(), self.path_and_query())

As far as implementation, it might be better to avoid the conditional for Eq:

impl PartialOrd for Uri {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for Uri {
    fn cmp(&self, r: &Self) -> Ordering {
        (self.authority(), self.scheme(), self.path_and_query())
            .cmp(&(r.authority(), r.scheme(), r.path_and_query()))
    }
}

...unless I'm missing something about that?

Users can still new-type the Uri (or Authority) to achieve alternative PartialOrd/Ord.

dekellum avatar Dec 12 '20 22:12 dekellum