use crate::console::ConsoleOptions;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Measurement {
pub minimum: usize,
pub maximum: usize,
}
impl Measurement {
pub fn new(minimum: usize, maximum: usize) -> Self {
Self { minimum, maximum }
}
pub fn with_maximum(self, maximum: usize) -> Self {
Self {
minimum: self.minimum.min(maximum),
maximum: self.maximum.min(maximum),
}
}
pub fn with_minimum(self, minimum: usize) -> Self {
Self {
minimum: self.minimum.max(minimum),
maximum: self.maximum.max(minimum),
}
}
pub fn shrink(self, amount: usize) -> Self {
Self {
minimum: self.minimum.saturating_sub(amount),
maximum: self.maximum.saturating_sub(amount),
}
}
pub fn grow(self, amount: usize) -> Self {
Self {
minimum: self.minimum + amount,
maximum: self.maximum + amount,
}
}
pub fn fixed(width: usize) -> Self {
Self {
minimum: width,
maximum: width,
}
}
}
pub trait Measurable {
fn measure(&self, options: &ConsoleOptions) -> Measurement;
}
impl Measurable for String {
fn measure(&self, _options: &ConsoleOptions) -> Measurement {
let w = unicode_width::UnicodeWidthStr::width(self.as_str());
Measurement::fixed(w)
}
}
impl Measurable for &str {
fn measure(&self, _options: &ConsoleOptions) -> Measurement {
let w = unicode_width::UnicodeWidthStr::width(*self);
Measurement::fixed(w)
}
}
pub fn measure_renderables<'a>(
items: impl IntoIterator<Item = &'a dyn Measurable>,
options: &ConsoleOptions,
) -> Measurement {
let mut min = 0usize;
let mut max = 0usize;
for item in items {
let m = item.measure(options);
min = min.max(m.minimum);
max = max.max(m.maximum);
}
Measurement::new(min, max)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_measurement_clamp() {
let m = Measurement::new(10, 100).with_maximum(50);
assert_eq!(m.minimum, 10);
assert_eq!(m.maximum, 50);
}
}