#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Constraint {
Fixed(u16),
Percentage(u16),
Min(u16),
Max(u16),
Fill(u16),
Ratio(u16, u16),
}
impl Constraint {
pub const fn fixed(n: u16) -> Self {
Self::Fixed(n)
}
pub const fn percentage(p: u16) -> Self {
Self::Percentage(p)
}
pub const fn min(n: u16) -> Self {
Self::Min(n)
}
pub const fn max(n: u16) -> Self {
Self::Max(n)
}
pub const fn fill(weight: u16) -> Self {
Self::Fill(weight)
}
pub const fn ratio(numerator: u16, denominator: u16) -> Self {
Self::Ratio(numerator, denominator)
}
pub fn is_flexible(&self) -> bool {
matches!(self, Self::Fill(_))
}
pub fn fill_weight(&self) -> u16 {
match self {
Self::Fill(w) => *w,
_ => 0,
}
}
pub fn resolve(&self, available: u16) -> (u16, bool) {
match self {
Self::Fixed(n) => ((*n).min(available), false),
Self::Percentage(p) => {
let size = (available as u32 * (*p).min(100) as u32 / 100) as u16;
(size, false)
}
Self::Min(n) => ((*n).min(available), false),
Self::Max(n) => ((*n).min(available), false),
Self::Fill(_) => (0, true), Self::Ratio(num, denom) => {
if *denom == 0 {
(0, false)
} else {
let size = (available as u32 * *num as u32 / *denom as u32) as u16;
(size.min(available), false)
}
}
}
}
}
impl Default for Constraint {
fn default() -> Self {
Self::Fill(1)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fixed_constraint() {
let c = Constraint::Fixed(10);
assert_eq!(c.resolve(100), (10, false));
assert_eq!(c.resolve(5), (5, false)); }
#[test]
fn test_percentage_constraint() {
let c = Constraint::Percentage(50);
assert_eq!(c.resolve(100), (50, false));
assert_eq!(c.resolve(80), (40, false));
}
#[test]
fn test_ratio_constraint() {
let c = Constraint::Ratio(1, 3);
assert_eq!(c.resolve(90), (30, false));
assert_eq!(c.resolve(100), (33, false)); }
#[test]
fn test_fill_constraint() {
let c = Constraint::Fill(1);
assert!(c.is_flexible());
assert_eq!(c.fill_weight(), 1);
assert_eq!(c.resolve(100), (0, true)); }
#[test]
fn test_ratio_zero_denominator() {
let c = Constraint::Ratio(1, 0);
assert_eq!(c.resolve(100), (0, false));
}
}