use super::Fixed;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum Dimension {
Px(Fixed),
Percent(Fixed),
#[default]
Auto,
Content,
}
impl Dimension {
#[inline(always)]
pub fn resolve(self, parent_size: Fixed) -> Option<Fixed> {
match self {
Self::Px(v) => Some(v),
Self::Percent(pct) => Some(parent_size * pct / Fixed::from_int(100)),
Self::Auto | Self::Content => None,
}
}
#[inline]
pub fn resolve_or(self, parent_size: Fixed, default: Fixed) -> Fixed {
self.resolve(parent_size).unwrap_or(default)
}
#[inline]
pub const fn px(v: i32) -> Self {
Self::Px(Fixed::from_int(v))
}
#[inline]
pub const fn percent(v: i32) -> Self {
Self::Percent(Fixed::from_int(v))
}
}
impl From<i32> for Dimension {
#[inline]
fn from(v: i32) -> Self {
Self::Px(Fixed::from_int(v))
}
}
impl From<u16> for Dimension {
#[inline]
fn from(v: u16) -> Self {
Self::Px(v.into())
}
}
impl From<Fixed> for Dimension {
#[inline]
fn from(v: Fixed) -> Self {
Self::Px(v)
}
}
impl core::ops::Add for Dimension {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
match (self, rhs) {
(Self::Px(a), Self::Px(b)) => Self::Px(a + b),
(Self::Percent(a), Self::Percent(b)) => Self::Percent(a + b),
_ => self,
}
}
}
impl core::ops::Sub for Dimension {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
match (self, rhs) {
(Self::Px(a), Self::Px(b)) => Self::Px(a - b),
(Self::Percent(a), Self::Percent(b)) => Self::Percent(a - b),
_ => self,
}
}
}
impl core::ops::Mul<Fixed> for Dimension {
type Output = Self;
#[inline]
fn mul(self, rhs: Fixed) -> Self {
match self {
Self::Px(v) => Self::Px(v * rhs),
Self::Percent(v) => Self::Percent(v * rhs),
other => other,
}
}
}
impl core::ops::Div<Fixed> for Dimension {
type Output = Self;
#[inline]
fn div(self, rhs: Fixed) -> Self {
match self {
Self::Px(v) => Self::Px(v / rhs),
Self::Percent(v) => Self::Percent(v / rhs),
other => other,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolve_px() {
let d = Dimension::Px(Fixed::from_int(50));
assert_eq!(d.resolve(Fixed::from_int(200)), Some(Fixed::from_int(50)));
}
#[test]
fn resolve_percent() {
let d = Dimension::Percent(Fixed::from_int(50));
let result = d.resolve(Fixed::from_int(200)).unwrap();
assert_eq!(result.to_int(), 100);
}
#[test]
fn resolve_percent_large_parent() {
for parent in [640, 1280, 1920, 4096, 8192] {
let got = Dimension::percent(100)
.resolve(Fixed::from_int(parent))
.unwrap();
assert_eq!(got.to_int(), parent, "Percent(100) on parent={parent}");
}
}
#[test]
fn resolve_percent_fraction_large_parent() {
let d = Dimension::percent(33);
let got = d.resolve(Fixed::from_int(1200)).unwrap();
assert_eq!(got.to_int(), 396);
}
#[test]
fn resolve_auto() {
assert_eq!(Dimension::Auto.resolve(Fixed::from_int(200)), None);
}
#[test]
fn from_i32() {
let d: Dimension = 100.into();
assert_eq!(d, Dimension::Px(Fixed::from_int(100)));
}
#[test]
fn add_px() {
let a = Dimension::Px(Fixed::from_int(10));
let b = Dimension::Px(Fixed::from_int(20));
assert_eq!((a + b), Dimension::Px(Fixed::from_int(30)));
}
#[test]
fn mul_fixed() {
let d = Dimension::Px(Fixed::from_int(10));
let result = d * Fixed::from_f32(1.5);
assert_eq!(result, Dimension::Px(Fixed::from_f32(15.0)));
}
}