7 releases

Uses old Rust 2015

0.1.0 Aug 11, 2016
0.0.6 Apr 7, 2015
0.0.4 Mar 9, 2015
0.0.3 Dec 23, 2014

#756 in Data structures

Download history 29488/week @ 2024-06-10 32451/week @ 2024-06-17 40022/week @ 2024-06-24 26886/week @ 2024-07-01 33945/week @ 2024-07-08 24338/week @ 2024-07-15 35089/week @ 2024-07-22 19914/week @ 2024-07-29 19962/week @ 2024-08-05 16190/week @ 2024-08-12 21695/week @ 2024-08-19 18525/week @ 2024-08-26 20840/week @ 2024-09-02 23276/week @ 2024-09-09 21192/week @ 2024-09-16 24052/week @ 2024-09-23

90,154 downloads per month
Used in 40 crates (20 directly)

MIT/Apache

20KB
173 lines

Experimental comparators for collections to be generic over.

Documentation is available at https://contain-rs.github.io/compare/compare.

To use compare with Cargo, add this to Cargo.toml:

[dependencies]
compare = "0.1"

and this to the crate root:

extern crate compare;

lib.rs:

Comparators.

A comparator is any type that implements the Compare trait, which imposes a total order. Its compare method accepts two values, which may be of the same type or different types, and returns an ordering on them.

Comparators are useful for parameterizing the behavior of sort methods and certain data structures.

The most basic comparator is Natural, which simply delegates to the type's implementation of [Ord] (http://doc.rust-lang.org/std/cmp/trait.Ord.html):

use compare::{Compare, natural};
use std::cmp::Ordering::{Less, Equal, Greater};

let a = &1;
let b = &2;

let cmp = natural();
assert_eq!(cmp.compare(a, b), Less);
assert_eq!(cmp.compare(b, a), Greater);
assert_eq!(cmp.compare(a, a), Equal);

There are convenience methods for checking each of the six relations:

use compare::{Compare, natural};

let a = &1;
let b = &2;

let cmp = natural();
assert!(cmp.compares_lt(a, b));
assert!(cmp.compares_le(a, b));
assert!(cmp.compares_ge(b, a));
assert!(cmp.compares_gt(b, a));
assert!(cmp.compares_eq(a, a));
assert!(cmp.compares_ne(a, b));

The Compare trait also provides default methods that consume a comparator to produce a new one with different behavior, similar to iterator adaptors. For example, all comparators can be reversed:

use compare::{Compare, natural};
use std::cmp::Ordering::Greater;

let cmp = natural().rev();
assert_eq!(cmp.compare(&1, &2), Greater);

It is possible to implement a comparator that is not based on the natural ordering of a type by using a closure of type Fn(&L, &R) -> Ordering. For example, slices can be compared by their length instead of their contents:

use compare::Compare;
use std::cmp::Ordering::{Less, Greater};

let a = [1, 2, 3];
let b = [4, 5];

let cmp = |l: &[i32], r: &[i32]| l.len().cmp(&r.len());
assert_eq!(cmp.compare(&a, &b), Greater);

let cmp = cmp.rev();
assert_eq!(cmp.compare(&a, &b), Less);

Comparators can be combined [lexicographically] (https://en.wikipedia.org/wiki/Lexicographical_order) in order to compare values first by one key, then, if the first keys were equal, by another:

use compare::Compare;
use std::cmp::Ordering::{Less, Equal, Greater};

struct Pet { name: &'static str, age: u8 }

let fido4 = &Pet { name: "Fido", age: 4 };
let ruff2 = &Pet { name: "Ruff", age: 2 };
let fido3 = &Pet { name: "Fido", age: 3 };

let name_cmp = |l: &Pet, r: &Pet| l.name.cmp(r.name);
assert_eq!(name_cmp.compare(fido4, ruff2), Less);
assert_eq!(name_cmp.compare(fido4, fido3), Equal);
assert_eq!(name_cmp.compare(ruff2, fido3), Greater);

let age_cmp = |l: &Pet, r: &Pet| l.age.cmp(&r.age);
assert_eq!(age_cmp.compare(fido4, ruff2), Greater);
assert_eq!(age_cmp.compare(fido4, fido3), Greater);
assert_eq!(age_cmp.compare(ruff2, fido3), Less);

let name_age_cmp = name_cmp.then(age_cmp);
assert_eq!(name_age_cmp.compare(fido4, ruff2), Less);
assert_eq!(name_age_cmp.compare(fido4, fido3), Greater);
assert_eq!(name_age_cmp.compare(ruff2, fido3), Greater);

It is often repetitive to compare two values of the same type by the same key, so the key-extraction logic can be factored out, simplifying the previous example:

use compare::{Compare, Extract};
use std::cmp::Ordering::{Less, Greater};

struct Pet { name: &'static str, age: u8 }

let fido4 = &Pet { name: "Fido", age: 4 };
let ruff2 = &Pet { name: "Ruff", age: 2 };
let fido3 = &Pet { name: "Fido", age: 3 };

let name_age_cmp = Extract::new(|p: &Pet| p.name)
             .then(Extract::new(|p: &Pet| p.age));

assert_eq!(name_age_cmp.compare(fido4, ruff2), Less);
assert_eq!(name_age_cmp.compare(fido4, fido3), Greater);
assert_eq!(name_age_cmp.compare(ruff2, fido3), Greater);

No runtime deps