sim_lib_discrete_graph/
cost.rs1use core::{cmp::Ordering, fmt::Debug};
4
5use crate::GraphError;
6
7pub trait FiniteCost: Clone + Debug + PartialEq + PartialOrd {
13 fn zero() -> Self;
15
16 fn checked_add(&self, rhs: &Self) -> Option<Self>;
18
19 fn is_finite(&self) -> bool {
21 true
22 }
23
24 fn compare(&self, rhs: &Self) -> Option<Ordering> {
26 self.partial_cmp(rhs)
27 }
28}
29
30macro_rules! integer_finite_cost {
31 ($($ty:ty),+ $(,)?) => {
32 $(
33 impl FiniteCost for $ty {
34 fn zero() -> Self {
35 0
36 }
37
38 fn checked_add(&self, rhs: &Self) -> Option<Self> {
39 (*self).checked_add(*rhs)
40 }
41 }
42 )+
43 };
44}
45
46integer_finite_cost!(
47 i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
48);
49
50macro_rules! float_finite_cost {
51 ($($ty:ty),+ $(,)?) => {
52 $(
53 impl FiniteCost for $ty {
54 fn zero() -> Self {
55 0.0
56 }
57
58 fn checked_add(&self, rhs: &Self) -> Option<Self> {
59 let value = *self + *rhs;
60 value.is_finite().then_some(value)
61 }
62
63 fn is_finite(&self) -> bool {
64 <$ty>::is_finite(*self)
65 }
66
67 fn compare(&self, rhs: &Self) -> Option<Ordering> {
68 (self.is_finite() && rhs.is_finite()).then(|| self.total_cmp(rhs))
69 }
70 }
71 )+
72 };
73}
74
75float_finite_cost!(f32, f64);
76
77pub(crate) fn add<C: FiniteCost>(left: &C, right: &C, context: &str) -> Result<C, GraphError> {
78 left.checked_add(right)
79 .filter(FiniteCost::is_finite)
80 .ok_or_else(|| GraphError::WeightOverflow(context.to_owned()))
81}
82
83pub(crate) fn compare<C: FiniteCost>(
84 left: &C,
85 right: &C,
86 context: &str,
87) -> Result<Ordering, GraphError> {
88 left.compare(right)
89 .ok_or_else(|| GraphError::NonFiniteCost(context.to_owned()))
90}
91
92pub(crate) fn validate<C: FiniteCost>(cost: &C, context: &str) -> Result<(), GraphError> {
93 if cost.is_finite() {
94 Ok(())
95 } else {
96 Err(GraphError::NonFiniteCost(context.to_owned()))
97 }
98}