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 fn to_level_numbers(&self) -> Vec<i64> {
67 vec![self.score]
68 }
69
70 fn from_level_numbers(levels: &[i64]) -> Self {
71 assert_eq!(levels.len(), 1, "SoftScore requires exactly 1 level");
72 SoftScore::of(levels[0])
73 }
74
75 impl_score_scale!(SoftScore { score } => of);
76
77 fn level_label(index: usize) -> ScoreLevel {
78 match index {
79 0 => ScoreLevel::Soft,
80 _ => panic!("SoftScore has 1 level, got index {}", index),
81 }
82 }
83
84 #[inline]
85 fn to_scalar(&self) -> f64 {
86 self.score as f64
87 }
88}
89
90impl Ord for SoftScore {
91 fn cmp(&self, other: &Self) -> Ordering {
92 self.score.cmp(&other.score)
93 }
94}
95
96impl_score_ops!(SoftScore { score } => of);
97
98impl fmt::Debug for SoftScore {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 write!(f, "SoftScore({})", self.score)
101 }
102}
103
104impl fmt::Display for SoftScore {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "{}", self.score)
107 }
108}
109
110impl ParseableScore for SoftScore {
112 fn parse(s: &str) -> Result<Self, ScoreParseError> {
113 let s = s.trim();
114 let s = s.strip_suffix("init").unwrap_or(s);
116
117 s.parse::<i64>()
118 .map(SoftScore::of)
119 .map_err(|e| ScoreParseError {
120 message: format!("Invalid SoftScore '{}': {}", s, e),
121 })
122 }
123
124 fn to_string_repr(&self) -> String {
125 self.score.to_string()
126 }
127}
128
129impl From<i64> for SoftScore {
130 fn from(score: i64) -> Self {
131 SoftScore::of(score)
132 }
133}