partial-cmp-derive
A procedural macro for deriving PartialEq, Eq, PartialOrd, Ord, and Hash with fine-grained control over field comparison and hashing behavior.
Features
- Consistent trait generation: All five traits are generated with consistent behavior
- Hash/Eq consistency: The
Hashimplementation respects the same field configuration asEq, ensuringa == b -> hash(a) == hash(b) - Skip fields: Exclude fields from all comparisons and hashing
- Key extraction: Use a single function to extract comparable keys for
Eq,Ord, andHash - Sort order control: Ascending or descending per field
- Field priority: Control comparison order independent of declaration order
- Explicit field ordering: Specify exactly which fields to compare and in what order
- Option handling: Control whether
Nonesorts first or last - Enum ranking: Control variant ordering independent of declaration order
- Trait selection: Opt out of specific traits as needed
Installation
[]
= "0.3"
Quick Start
use PartialCmp;
// Generates PartialEq, Eq, PartialOrd, Ord, and Hash
let alice = Player ;
let bob = Player ;
// id is ignored, score compared first (desc), then name (asc)
assert!; // Same score, Alice < Bob alphabetically
// Equality also ignores id
let alice2 = Player ;
assert_eq!; // Same score and name, different id - equal!
Attributes
Struct-Level Attributes
| Attribute | Description |
|---|---|
#[ord(reverse)] |
Reverse the final comparison result |
#[ord(by = [field1(asc), field2(desc)])] |
Explicit field comparison order |
#[ord(skip_partial_eq)] |
Don't generate PartialEq (implies no other traits) |
#[ord(skip_eq)] |
Don't generate Eq (also disables Ord and Hash) |
#[ord(skip_partial_ord)] |
Don't generate PartialOrd (also disables Ord) |
#[ord(skip_ord)] |
Don't generate Ord |
#[ord(skip_hash)] |
Don't generate Hash |
Field-Level Attributes
| Attribute | Description |
|---|---|
#[ord(skip)] |
Exclude from all comparisons and hashing |
#[ord(order = "asc"|"desc")] |
Sort direction (default: asc) |
#[ord(priority = N)] |
Comparison priority (lower = compared first) |
#[ord(key = "path::to::fn")] |
Key extraction function fn(&T) -> U |
#[ord(none_order = "first"|"last")] |
Where None sorts for Option fields |
Enum Variant Attributes
| Attribute | Description |
|---|---|
#[ord(rank = N)] |
Variant ranking (lower = less than) |
Examples
Skipping Fields
Fields marked with #[ord(skip)] are excluded from equality, ordering, and hash computations:
use PartialCmp;
let a = Record ;
let b = Record ;
assert_eq!; // Equal because only value is compared
Explicit Field Ordering
Use by to specify exactly which fields participate in comparison:
use PartialCmp;
Key Extraction
The key attribute allows you to specify a function that extracts a comparable value from a field. This single function is used for Eq, Ord, and Hash, ensuring consistency automatically:
use PartialCmp;
let a = AbsValue ;
let b = AbsValue ;
assert_eq!; // Equal because abs(-5) == abs(5)
// And their hashes are also equal, maintaining the Hash/Eq invariant
The key function signature should be fn(&T) -> U where U: Ord + Hash.
Option Handling
use PartialCmp;
let none = MaybeValue ;
let some = MaybeValue ;
assert!; // None comes first
Enum Ranking
use PartialCmp;
assert!;
assert!;
Working with Non-Ord Types
For types like f32 that don't implement Ord or Hash, you can use a key function to convert them, or skip the relevant traits:
use PartialCmp;
// Convert f32 to ordered bits for comparison
Or skip traits that aren't needed:
use PartialCmp;
// Only generate PartialEq and PartialOrd
Trait Dependencies
The trait generation respects the following dependencies:
OrdrequiresEqandPartialOrdEqandPartialOrdrequirePartialEqHashis independent but should be consistent withEq
When you skip a trait, dependent traits are automatically skipped:
| Skip Flag | Traits Generated |
|---|---|
| (none) | PartialEq, Eq, PartialOrd, Ord, Hash |
skip_ord |
PartialEq, Eq, PartialOrd, Hash |
skip_eq |
PartialEq, PartialOrd, Hash |
skip_partial_ord |
PartialEq, Eq, Hash |
skip_hash |
PartialEq, Eq, PartialOrd, Ord |
skip_eq, skip_ord |
PartialEq, PartialOrd, Hash |
skip_partial_eq |
(none) |
License
MIT