use crate::UiNum;
crate::bound_int! {
#[doc = crate::_tags!(ui layout quant)]
#[doc = crate::_doc_meta!{
location("ui/layout", struct Lunit),
test_size_of(Lunit = 4|32; niche !Option),
}]
pub struct Lunit: repr(i32 => i32);
value_bits(32-4);
range(symmetric);
ops(all);
impl {
pub const QUANTA_PER_LOGICAL_PX: i32 = 120;
pub const fn px(px: i32) -> Self {
Self::new_saturated_up((px as i64).saturating_mul(Self::QUANTA_PER_LOGICAL_PX as i64))
}
pub const fn px_frac(num: i32, den: i32) -> Self {
if den == 0 {
return if num < 0 { Self::MIN } else if num > 0 { Self::MAX } else { Self::ZERO }; }
let n = (num as i64).saturating_mul(Self::QUANTA_PER_LOGICAL_PX as i64);
Self::new_saturated_up(UiNum::div_nearest_i64(n, den as i64))
}
pub const fn from_quanta(quanta: i32) -> Self { Self::new_saturated(quanta) }
pub const fn quanta(self) -> i32 { self.get() }
pub const fn positive_part(self) -> Self {
self.max_zero()
}
pub const fn sub_floor_zero(self, rhs: Self) -> Self {
self.sat_sub(rhs).max_zero()
}
pub const fn div_floor_i32(self, rhs: i32) -> Self {
if rhs == 0 { return if self.is_negative() { Self::MIN } else { Self::MAX }; }
Self::new_saturated_up(UiNum::div_floor_i64(self.get() as i64, rhs as i64))
}
pub const fn div_ceil_i32(self, rhs: i32) -> Self {
if rhs == 0 { return if self.is_negative() { Self::MIN } else { Self::MAX }; }
Self::new_saturated_up(UiNum::div_ceil_i64(self.get() as i64, rhs as i64))
}
pub const fn div_round_i32(self, rhs: i32) -> Self {
if rhs == 0 { return if self.is_negative() { Self::MIN } else { Self::MAX }; }
Self::new_saturated_up(UiNum::div_nearest_i64(self.get() as i64, rhs as i64))
}
pub const fn split_floor(self, parts: i32) -> Self {
if parts <= 0 { Self::ZERO } else { self.div_floor_i32(parts) }
}
pub const fn split_remainder(self, parts: i32) -> i32 {
if parts <= 0 { 0 } else { self.get() % parts }
}
}
}
#[cfg(test)]
mod _test {
use super::*;
#[test]
fn px_construction() {
assert_eq!(Lunit::px(0).quanta(), 0);
assert_eq!(Lunit::px(1).quanta(), Lunit::QUANTA_PER_LOGICAL_PX);
assert_eq!(Lunit::px(-1).quanta(), -Lunit::QUANTA_PER_LOGICAL_PX);
}
#[test]
fn px_frac_construction() {
assert_eq!(Lunit::px_frac(1, 2).quanta(), Lunit::QUANTA_PER_LOGICAL_PX / 2);
assert_eq!(Lunit::px_frac(1, 4).quanta(), Lunit::QUANTA_PER_LOGICAL_PX / 4);
assert_eq!(Lunit::px_frac(-1, 2).quanta(), -Lunit::QUANTA_PER_LOGICAL_PX / 2);
}
#[test]
fn sub_floor_zero() {
assert_eq!(Lunit::px(10).sub_floor_zero(Lunit::px(3)), Lunit::px(7));
assert_eq!(Lunit::px(3).sub_floor_zero(Lunit::px(10)), Lunit::ZERO);
}
#[test]
fn split_floor_and_remainder() {
let total = Lunit::px(10);
let part = total.split_floor(3);
let rem = total.split_remainder(3);
assert_eq!(part.quanta(), total.quanta() / 3);
assert_eq!(rem, total.quanta() % 3);
}
#[test]
fn split_invalid_parts() {
assert_eq!(Lunit::px(10).split_floor(0), Lunit::ZERO);
assert_eq!(Lunit::px(10).split_remainder(0), 0);
assert_eq!(Lunit::px(10).split_floor(-3), Lunit::ZERO);
assert_eq!(Lunit::px(10).split_remainder(-3), 0);
}
}