diff --git a/docs/release_notes/upcoming.md b/docs/release_notes/upcoming.md index 6d94973c4..3bb071243 100644 --- a/docs/release_notes/upcoming.md +++ b/docs/release_notes/upcoming.md @@ -54,6 +54,8 @@ ready to be released, carry out the following steps: - Users can now set demand to zero in `demand.csv` ([#871]) - Fix: sign for levies of type `net` was wrong for inputs ([#969]) - Fix `--overwrite` option for `save-graphs` command ([#1001]) +- Fix broken `Eq`/`Ord` consistency for `AssetCapacity`: equality is now aligned with + `total_cmp` ordering ([#1158]) [#767]: https://github.com/EnergySystemsModellingLab/MUSE2/pull/767 [#868]: https://github.com/EnergySystemsModellingLab/MUSE2/pull/868 @@ -72,3 +74,4 @@ ready to be released, carry out the following steps: [#1021]: https://github.com/EnergySystemsModellingLab/MUSE2/pull/1021 [#1022]: https://github.com/EnergySystemsModellingLab/MUSE2/pull/1022 [#1030]: https://github.com/EnergySystemsModellingLab/MUSE2/pull/1030 +[#1158]: https://github.com/EnergySystemsModellingLab/MUSE2/pull/1158 diff --git a/src/asset/capacity.rs b/src/asset/capacity.rs index d0ae3127c..3e1382969 100644 --- a/src/asset/capacity.rs +++ b/src/asset/capacity.rs @@ -4,7 +4,7 @@ use std::cmp::Ordering; use std::ops::{Add, Sub}; /// Capacity of an asset, which may be continuous or a discrete number of indivisible units -#[derive(Clone, PartialEq, Copy, Debug)] +#[derive(Clone, Copy, Debug)] pub enum AssetCapacity { /// Continuous capacity Continuous(Capacity), @@ -13,6 +13,12 @@ pub enum AssetCapacity { Discrete(u32, Capacity), } +impl PartialEq for AssetCapacity { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + impl Add for AssetCapacity { type Output = Self; @@ -213,4 +219,41 @@ mod tests { let got = orig.apply_limit_factor(factor); assert_eq!(got, AssetCapacity::Discrete(expected_units, unit_size)); } + + /// `PartialEq` must be consistent with `Ord`: two values are equal iff `cmp` returns + /// `Ordering::Equal`. + #[rstest] + #[case::continuous_equal( + AssetCapacity::Continuous(Capacity(1.0)), + AssetCapacity::Continuous(Capacity(1.0)), + true + )] + #[case::continuous_positive_zero_vs_negative_zero( + AssetCapacity::Continuous(Capacity(0.0)), + AssetCapacity::Continuous(Capacity(-0.0)), + false + )] + #[case::continuous_unequal( + AssetCapacity::Continuous(Capacity(1.0)), + AssetCapacity::Continuous(Capacity(2.0)), + false + )] + #[case::discrete_equal( + AssetCapacity::Discrete(3, Capacity(4.0)), + AssetCapacity::Discrete(3, Capacity(4.0)), + true + )] + #[case::discrete_unequal( + AssetCapacity::Discrete(2, Capacity(4.0)), + AssetCapacity::Discrete(3, Capacity(4.0)), + false + )] + fn eq_consistent_with_ord( + #[case] a: AssetCapacity, + #[case] b: AssetCapacity, + #[case] expected_eq: bool, + ) { + assert_eq!(a == b, expected_eq); + assert_eq!(a.cmp(&b) == Ordering::Equal, expected_eq); + } }