use crate::console::RenderContext;
use crate::renderable::Renderable;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Measurement {
pub minimum: usize,
pub maximum: usize,
pub lines: usize,
}
impl Measurement {
pub fn new(minimum: usize, maximum: usize, lines: usize) -> Self {
Measurement {
minimum,
maximum,
lines,
}
}
pub fn measure(renderable: &impl Renderable, width: usize) -> Self {
let context = RenderContext {
width,
height: None,
};
let segments = renderable.render(&context);
let lines = segments.len();
let minimum = renderable.min_width();
let maximum = renderable.max_width().min(width);
Measurement {
minimum,
maximum,
lines,
}
}
pub fn aspect_ratio(&self) -> f64 {
if self.lines == 0 {
0.0
} else {
self.maximum as f64 / self.lines as f64
}
}
pub fn fits(&self, width: usize, height: usize) -> bool {
self.minimum <= width && self.lines <= height
}
pub fn area(&self) -> usize {
self.maximum * self.lines
}
}
pub trait Measurable {
fn measure(&self, width: usize) -> Measurement;
}
impl<T: Renderable> Measurable for T {
fn measure(&self, width: usize) -> Measurement {
Measurement::measure(self, width)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::text::Text;
#[test]
fn test_measurement_creation() {
let m = Measurement::new(10, 50, 3);
assert_eq!(m.minimum, 10);
assert_eq!(m.maximum, 50);
assert_eq!(m.lines, 3);
}
#[test]
fn test_measure_text() {
let text = Text::plain("Hello, World!");
let m = Measurement::measure(&text, 80);
assert!(m.minimum > 0);
assert!(m.lines > 0);
}
#[test]
fn test_aspect_ratio() {
let m = Measurement::new(20, 40, 5);
assert_eq!(m.aspect_ratio(), 8.0);
}
#[test]
fn test_fits() {
let m = Measurement::new(10, 40, 3);
assert!(m.fits(50, 5));
assert!(!m.fits(5, 5)); assert!(!m.fits(50, 2)); }
#[test]
fn test_area() {
let m = Measurement::new(10, 20, 5);
assert_eq!(m.area(), 100); }
}