#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Scale(u32);
impl Scale {
pub const ONE: Scale = Scale(1);
pub fn new(factor: i32) -> Scale {
Scale(factor.max(1) as u32)
}
pub fn get(self) -> u32 {
self.0
}
pub fn to_physical(self, logical: u32) -> u32 {
logical.saturating_mul(self.0)
}
pub fn to_physical_size(self, width: u32, height: u32) -> (u32, u32) {
(self.to_physical(width), self.to_physical(height))
}
pub fn scale_font(self, size: f32) -> f32 {
size * self.0 as f32
}
}
impl Default for Scale {
fn default() -> Self {
Scale::ONE
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one_is_the_identity_scale() {
assert_eq!(Scale::ONE.get(), 1);
assert_eq!(Scale::ONE.to_physical(32), 32);
assert_eq!(Scale::ONE.to_physical_size(1920, 32), (1920, 32));
assert_eq!(Scale::ONE.scale_font(16.0), 16.0);
assert_eq!(Scale::default(), Scale::ONE);
}
#[test]
fn new_clamps_non_positive_factors_to_one() {
assert_eq!(Scale::new(0), Scale::ONE);
assert_eq!(Scale::new(-3), Scale::ONE);
assert_eq!(Scale::new(1), Scale::ONE);
}
#[test]
fn to_physical_multiplies_logical_by_the_factor() {
let scale = Scale::new(2);
assert_eq!(scale.get(), 2);
assert_eq!(scale.to_physical(32), 64);
assert_eq!(scale.to_physical(0), 0);
}
#[test]
fn to_physical_size_scales_both_axes() {
assert_eq!(Scale::new(2).to_physical_size(1920, 32), (3840, 64));
assert_eq!(Scale::new(3).to_physical_size(100, 10), (300, 30));
}
#[test]
fn scale_font_multiplies_the_logical_size() {
assert_eq!(Scale::new(2).scale_font(16.0), 32.0);
assert_eq!(Scale::new(3).scale_font(10.5), 31.5);
}
#[test]
fn to_physical_saturates_instead_of_overflowing() {
assert_eq!(Scale::new(4).to_physical(u32::MAX), u32::MAX);
}
}