#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GlassTintAmount(f32);
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
#[error("glass tint amount must be finite and between 0 and 100 percent")]
pub struct InvalidGlassTintAmount;
impl GlassTintAmount {
pub fn from_percent(percent: f32) -> Result<Self, InvalidGlassTintAmount> {
if percent.is_finite() && (0.0..=100.0).contains(&percent) {
Ok(Self(percent))
} else {
Err(InvalidGlassTintAmount)
}
}
pub fn percent(self) -> f32 {
self.0
}
}
impl Default for GlassTintAmount {
fn default() -> Self {
Self(25.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tint_accepts_calibration_levels_and_intermediate_values() {
for percent in [0.0, 12.5, 20.0, 25.0, 50.0, 75.0, 100.0] {
assert_eq!(
GlassTintAmount::from_percent(percent).unwrap().percent(),
percent
);
}
assert_eq!(GlassTintAmount::default().percent(), 25.0);
}
#[test]
fn tint_rejects_invalid_percentages() {
for percent in [-0.01, 100.01, f32::NAN, f32::INFINITY, f32::NEG_INFINITY] {
assert_eq!(
GlassTintAmount::from_percent(percent),
Err(InvalidGlassTintAmount)
);
}
assert_eq!(
InvalidGlassTintAmount.to_string(),
"glass tint amount must be finite and between 0 and 100 percent"
);
}
}