solverforge_core/score/
soft.rs1use std::cmp::Ordering;
4use std::fmt;
5
6use super::traits::{ParseableScore, Score, ScoreParseError};
7use super::ScoreLevel;
8
9#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub struct SoftScore {
29 score: i64,
30}
31
32impl SoftScore {
33 pub const ZERO: SoftScore = SoftScore { score: 0 };
35
36 pub const ONE: SoftScore = SoftScore { score: 1 };
38
39 #[inline]
40 pub const fn of(score: i64) -> Self {
41 SoftScore { score }
42 }
43
44 #[inline]
45 pub const fn score(&self) -> i64 {
46 self.score
47 }
48}
49
50impl Score for SoftScore {
51 #[inline]
52 fn is_feasible(&self) -> bool {
53 self.score >= 0
54 }
55
56 #[inline]
57 fn zero() -> Self {
58 SoftScore::ZERO
59 }
60
61 #[inline]
62 fn levels_count() -> usize {
63 1
64 }
65
66 #[inline]
67 fn level_number(&self, index: usize) -> i64 {
68 match index {
69 0 => self.score,
70 _ => panic!("SoftScore has 1 level, got index {}", index),
71 }
72 }
73
74 fn from_level_numbers(levels: &[i64]) -> Self {
75 assert_eq!(levels.len(), 1, "SoftScore requires exactly 1 level");
76 SoftScore::of(levels[0])
77 }
78
79 impl_score_scale!(SoftScore { score } => of);
80
81 fn level_label(index: usize) -> ScoreLevel {
82 match index {
83 0 => ScoreLevel::Soft,
84 _ => panic!("SoftScore has 1 level, got index {}", index),
85 }
86 }
87
88 #[inline]
89 fn to_scalar(&self) -> f64 {
90 self.score as f64
91 }
92}
93
94impl Ord for SoftScore {
95 fn cmp(&self, other: &Self) -> Ordering {
96 self.score.cmp(&other.score)
97 }
98}
99
100impl_score_ops!(SoftScore { score } => of);
101
102impl fmt::Debug for SoftScore {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 write!(f, "SoftScore({})", self.score)
105 }
106}
107
108impl fmt::Display for SoftScore {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(f, "{}", self.score)
111 }
112}
113
114impl ParseableScore for SoftScore {
116 fn parse(s: &str) -> Result<Self, ScoreParseError> {
117 let s = s.trim();
118 let s = s.strip_suffix("init").unwrap_or(s);
120
121 s.parse::<i64>()
122 .map(SoftScore::of)
123 .map_err(|e| ScoreParseError {
124 message: format!("Invalid SoftScore '{}': {}", s, e),
125 })
126 }
127
128 fn to_string_repr(&self) -> String {
129 self.score.to_string()
130 }
131}
132
133impl From<i64> for SoftScore {
134 fn from(score: i64) -> Self {
135 SoftScore::of(score)
136 }
137}