fix(layout): cap Contstraint::apply to 100% length (#264)

This function is only currently used in by the chart widget for
constraining the width and height of the legend.
This commit is contained in:
Ende 2023-06-17 03:44:13 -07:00 committed by GitHub
parent dca9871744
commit 28a8435a52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -27,7 +27,6 @@ pub enum Direction {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Constraint { pub enum Constraint {
// TODO: enforce range 0 - 100
Percentage(u16), Percentage(u16),
Ratio(u32, u32), Ratio(u32, u32),
Length(u16), Length(u16),
@ -38,10 +37,17 @@ pub enum Constraint {
impl Constraint { impl Constraint {
pub fn apply(&self, length: u16) -> u16 { pub fn apply(&self, length: u16) -> u16 {
match *self { match *self {
Constraint::Percentage(p) => length * p / 100, Constraint::Percentage(p) => {
Constraint::Ratio(num, den) => { let p = p as f32 / 100.0;
let r = num * u32::from(length) / den; let length = length as f32;
r as u16 (p * length).min(length) as u16
}
Constraint::Ratio(numerator, denominator) => {
// avoid division by zero by using 1 when denominator is 0
// this results in 0/0 -> 0 and x/0 -> x for x != 0
let percentage = numerator as f32 / denominator.max(1) as f32;
let length = length as f32;
(percentage * length).min(length) as u16
} }
Constraint::Length(l) => length.min(l), Constraint::Length(l) => length.min(l),
Constraint::Max(m) => length.min(m), Constraint::Max(m) => length.min(m),
@ -555,4 +561,41 @@ mod tests {
assert_eq!(rect.width, 300); assert_eq!(rect.width, 300);
assert_eq!(rect.height, 100); assert_eq!(rect.height, 100);
} }
#[test]
fn test_constraint_apply() {
assert_eq!(Constraint::Percentage(0).apply(100), 0);
assert_eq!(Constraint::Percentage(50).apply(100), 50);
assert_eq!(Constraint::Percentage(100).apply(100), 100);
assert_eq!(Constraint::Percentage(200).apply(100), 100);
assert_eq!(Constraint::Percentage(u16::MAX).apply(100), 100);
// 0/0 intentionally avoids a panic by returning 0.
assert_eq!(Constraint::Ratio(0, 0).apply(100), 0);
// 1/0 intentionally avoids a panic by returning 100% of the length.
assert_eq!(Constraint::Ratio(1, 0).apply(100), 100);
assert_eq!(Constraint::Ratio(0, 1).apply(100), 0);
assert_eq!(Constraint::Ratio(1, 2).apply(100), 50);
assert_eq!(Constraint::Ratio(2, 2).apply(100), 100);
assert_eq!(Constraint::Ratio(3, 2).apply(100), 100);
assert_eq!(Constraint::Ratio(u32::MAX, 2).apply(100), 100);
assert_eq!(Constraint::Length(0).apply(100), 0);
assert_eq!(Constraint::Length(50).apply(100), 50);
assert_eq!(Constraint::Length(100).apply(100), 100);
assert_eq!(Constraint::Length(200).apply(100), 100);
assert_eq!(Constraint::Length(u16::MAX).apply(100), 100);
assert_eq!(Constraint::Max(0).apply(100), 0);
assert_eq!(Constraint::Max(50).apply(100), 50);
assert_eq!(Constraint::Max(100).apply(100), 100);
assert_eq!(Constraint::Max(200).apply(100), 100);
assert_eq!(Constraint::Max(u16::MAX).apply(100), 100);
assert_eq!(Constraint::Min(0).apply(100), 100);
assert_eq!(Constraint::Min(50).apply(100), 100);
assert_eq!(Constraint::Min(100).apply(100), 100);
assert_eq!(Constraint::Min(200).apply(100), 200);
assert_eq!(Constraint::Min(u16::MAX).apply(100), u16::MAX);
}
} }