1use crate::console::RenderContext;
6use crate::renderable::Renderable;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct Measurement {
11 pub minimum: usize,
13 pub maximum: usize,
15 pub lines: usize,
17}
18
19impl Measurement {
20 pub fn new(minimum: usize, maximum: usize, lines: usize) -> Self {
22 Measurement {
23 minimum,
24 maximum,
25 lines,
26 }
27 }
28
29 pub fn measure(renderable: &impl Renderable, width: usize) -> Self {
31 let context = RenderContext {
32 width,
33 height: None,
34 };
35 let segments = renderable.render(&context);
36
37 let lines = segments.len();
38 let minimum = renderable.min_width();
39 let maximum = renderable.max_width().min(width);
40
41 Measurement {
42 minimum,
43 maximum,
44 lines,
45 }
46 }
47
48 pub fn aspect_ratio(&self) -> f64 {
50 if self.lines == 0 {
51 0.0
52 } else {
53 self.maximum as f64 / self.lines as f64
54 }
55 }
56
57 pub fn fits(&self, width: usize, height: usize) -> bool {
59 self.minimum <= width && self.lines <= height
60 }
61
62 pub fn area(&self) -> usize {
64 self.maximum * self.lines
65 }
66}
67
68pub trait Measurable {
70 fn measure(&self, width: usize) -> Measurement;
72}
73
74impl<T: Renderable> Measurable for T {
75 fn measure(&self, width: usize) -> Measurement {
76 Measurement::measure(self, width)
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use crate::text::Text;
84
85 #[test]
86 fn test_measurement_creation() {
87 let m = Measurement::new(10, 50, 3);
88 assert_eq!(m.minimum, 10);
89 assert_eq!(m.maximum, 50);
90 assert_eq!(m.lines, 3);
91 }
92
93 #[test]
94 fn test_measure_text() {
95 let text = Text::plain("Hello, World!");
96 let m = Measurement::measure(&text, 80);
97
98 assert!(m.minimum > 0);
99 assert!(m.lines > 0);
100 }
101
102 #[test]
103 fn test_aspect_ratio() {
104 let m = Measurement::new(20, 40, 5);
105 assert_eq!(m.aspect_ratio(), 8.0);
106 }
107
108 #[test]
109 fn test_fits() {
110 let m = Measurement::new(10, 40, 3);
111 assert!(m.fits(50, 5));
112 assert!(!m.fits(5, 5)); assert!(!m.fits(50, 2)); }
115
116 #[test]
117 fn test_area() {
118 let m = Measurement::new(10, 20, 5);
119 assert_eq!(m.area(), 100); }
121}