use std::cmp::Ordering;
use std::fmt;
use super::traits::Score;
use super::ScoreLevel;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HardMediumSoftScore {
hard: i64,
medium: i64,
soft: i64,
}
impl HardMediumSoftScore {
pub const ZERO: HardMediumSoftScore = HardMediumSoftScore {
hard: 0,
medium: 0,
soft: 0,
};
pub const ONE_HARD: HardMediumSoftScore = HardMediumSoftScore {
hard: 1,
medium: 0,
soft: 0,
};
pub const ONE_MEDIUM: HardMediumSoftScore = HardMediumSoftScore {
hard: 0,
medium: 1,
soft: 0,
};
pub const ONE_SOFT: HardMediumSoftScore = HardMediumSoftScore {
hard: 0,
medium: 0,
soft: 1,
};
#[inline]
pub const fn of(hard: i64, medium: i64, soft: i64) -> Self {
HardMediumSoftScore { hard, medium, soft }
}
#[inline]
pub const fn of_hard(hard: i64) -> Self {
HardMediumSoftScore {
hard,
medium: 0,
soft: 0,
}
}
#[inline]
pub const fn of_medium(medium: i64) -> Self {
HardMediumSoftScore {
hard: 0,
medium,
soft: 0,
}
}
#[inline]
pub const fn of_soft(soft: i64) -> Self {
HardMediumSoftScore {
hard: 0,
medium: 0,
soft,
}
}
#[inline]
pub const fn hard(&self) -> i64 {
self.hard
}
#[inline]
pub const fn medium(&self) -> i64 {
self.medium
}
#[inline]
pub const fn soft(&self) -> i64 {
self.soft
}
}
impl Score for HardMediumSoftScore {
#[inline]
fn is_feasible(&self) -> bool {
self.hard >= 0
}
#[inline]
fn zero() -> Self {
HardMediumSoftScore::ZERO
}
#[inline]
fn levels_count() -> usize {
3
}
fn to_level_numbers(&self) -> Vec<i64> {
vec![self.hard, self.medium, self.soft]
}
fn from_level_numbers(levels: &[i64]) -> Self {
assert_eq!(
levels.len(),
3,
"HardMediumSoftScore requires exactly 3 levels"
);
HardMediumSoftScore::of(levels[0], levels[1], levels[2])
}
impl_score_scale!(HardMediumSoftScore { hard, medium, soft } => of);
fn level_label(index: usize) -> ScoreLevel {
match index {
0 => ScoreLevel::Hard,
1 => ScoreLevel::Medium,
2 => ScoreLevel::Soft,
_ => panic!("HardMediumSoftScore has 3 levels, got index {}", index),
}
}
#[inline]
fn to_scalar(&self) -> f64 {
self.hard as f64 * 1_000_000_000_000.0 + self.medium as f64 * 1_000_000.0 + self.soft as f64
}
}
impl Ord for HardMediumSoftScore {
fn cmp(&self, other: &Self) -> Ordering {
match self.hard.cmp(&other.hard) {
Ordering::Equal => match self.medium.cmp(&other.medium) {
Ordering::Equal => self.soft.cmp(&other.soft),
other => other,
},
other => other,
}
}
}
impl_score_ops!(HardMediumSoftScore { hard, medium, soft } => of);
impl fmt::Debug for HardMediumSoftScore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"HardMediumSoftScore({}, {}, {})",
self.hard, self.medium, self.soft
)
}
}
impl fmt::Display for HardMediumSoftScore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}hard/{}medium/{}soft",
self.hard, self.medium, self.soft
)
}
}
impl_score_parse!(HardMediumSoftScore { hard => "hard", medium => "medium", soft => "soft" } => of);