use std::any::Any; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not}; use super::*; /// A container with a horizontal and vertical component. #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct Spec { /// The horizontal component. pub x: T, /// The vertical component. pub y: T, } impl Spec { /// Create a new instance from the two components. pub const fn new(x: T, y: T) -> Self { Self { x, y } } /// Create a new instance with two equal components. pub fn splat(v: T) -> Self where T: Clone, { Self { x: v.clone(), y: v } } /// Maps the individual fields with `f`. pub fn map(self, mut f: F) -> Spec where F: FnMut(T) -> U, { Spec { x: f(self.x), y: f(self.y) } } /// Convert from `&Spec` to `Spec<&T>`. pub fn as_ref(&self) -> Spec<&T> { Spec { x: &self.x, y: &self.y } } /// Convert from `&mut Spec` to `Spec<&mut T>`. pub fn as_mut(&mut self) -> Spec<&mut T> { Spec { x: &mut self.x, y: &mut self.y } } /// Zip two instances into an instance over a tuple. pub fn zip(self, other: Spec) -> Spec<(T, U)> { Spec { x: (self.x, other.x), y: (self.y, other.y), } } /// Whether a condition is true for at least one of fields. pub fn any(self, mut f: F) -> bool where F: FnMut(&T) -> bool, { f(&self.x) || f(&self.y) } /// Whether a condition is true for both fields. pub fn all(self, mut f: F) -> bool where F: FnMut(&T) -> bool, { f(&self.x) && f(&self.y) } /// Filter the individual fields with a mask. pub fn filter(self, mask: Spec) -> Spec> { Spec { x: if mask.x { Some(self.x) } else { None }, y: if mask.y { Some(self.y) } else { None }, } } /// Convert to the generic representation. pub fn to_gen(self, main: SpecAxis) -> Gen { match main { SpecAxis::Horizontal => Gen::new(self.y, self.x), SpecAxis::Vertical => Gen::new(self.x, self.y), } } } impl Spec { /// Create a new instance with y set to its default value. pub fn with_x(x: T) -> Self { Self { x, y: T::default() } } /// Create a new instance with x set to its default value. pub fn with_y(y: T) -> Self { Self { x: T::default(), y } } } impl Spec { /// The component-wise minimum of this and another instance. pub fn min(self, other: Self) -> Self { Self { x: self.x.min(other.x), y: self.y.min(other.y), } } /// The component-wise minimum of this and another instance. pub fn max(self, other: Self) -> Self { Self { x: self.x.max(other.x), y: self.y.max(other.y), } } } impl Get for Spec { type Component = T; fn get(self, axis: SpecAxis) -> T { match axis { SpecAxis::Horizontal => self.x, SpecAxis::Vertical => self.y, } } fn get_mut(&mut self, axis: SpecAxis) -> &mut T { match axis { SpecAxis::Horizontal => &mut self.x, SpecAxis::Vertical => &mut self.y, } } } impl Debug for Spec where T: Debug + 'static, { fn fmt(&self, f: &mut Formatter) -> fmt::Result { if let Spec { x: Some(x), y: Some(y) } = self.as_ref().map(|v| (v as &dyn Any).downcast_ref::()) { write!(f, "{:?}-{:?}", x, y) } else if (&self.x as &dyn Any).is::() { write!(f, "Size({:?}, {:?})", self.x, self.y) } else { write!(f, "Spec({:?}, {:?})", self.x, self.y) } } } /// The two specific layouting axes. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub enum SpecAxis { /// The horizontal layouting axis. Horizontal, /// The vertical layouting axis. Vertical, } impl SpecAxis { /// The direction with the given positivity for this axis. pub fn dir(self, positive: bool) -> Dir { match (self, positive) { (Self::Horizontal, true) => Dir::LTR, (Self::Horizontal, false) => Dir::RTL, (Self::Vertical, true) => Dir::TTB, (Self::Vertical, false) => Dir::BTT, } } /// The other axis. pub fn other(self) -> Self { match self { Self::Horizontal => Self::Vertical, Self::Vertical => Self::Horizontal, } } } impl Debug for SpecAxis { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.pad(match self { Self::Horizontal => "horizontal", Self::Vertical => "vertical", }) } } /// A size in 2D. pub type Size = Spec; impl Size { /// The zero value. pub fn zero() -> Self { Self { x: Length::zero(), y: Length::zero() } } /// Whether the other size fits into this one (smaller width and height). pub fn fits(self, other: Self) -> bool { self.x.fits(other.x) && self.y.fits(other.y) } /// Whether both components are zero. pub fn is_zero(self) -> bool { self.x.is_zero() && self.y.is_zero() } /// Whether both components are finite. pub fn is_finite(self) -> bool { self.x.is_finite() && self.y.is_finite() } /// Whether any of the two components is infinite. pub fn is_infinite(self) -> bool { self.x.is_infinite() || self.y.is_infinite() } /// Convert to a point. pub fn to_point(self) -> Point { Point::new(self.x, self.y) } } impl Neg for Size { type Output = Self; fn neg(self) -> Self { Self { x: -self.x, y: -self.y } } } impl Add for Size { type Output = Self; fn add(self, other: Self) -> Self { Self { x: self.x + other.x, y: self.y + other.y } } } sub_impl!(Size - Size -> Size); impl Mul for Size { type Output = Self; fn mul(self, other: f64) -> Self { Self { x: self.x * other, y: self.y * other } } } impl Mul for f64 { type Output = Size; fn mul(self, other: Size) -> Size { other * self } } impl Div for Size { type Output = Self; fn div(self, other: f64) -> Self { Self { x: self.x / other, y: self.y / other } } } assign_impl!(Size -= Size); assign_impl!(Size += Size); assign_impl!(Size *= f64); assign_impl!(Size /= f64); impl Spec> { /// Whether the individual fields are some. pub fn map_is_some(&self) -> Spec { self.as_ref().map(Option::is_some) } /// Whether the individual fields are none. pub fn map_is_none(&self) -> Spec { self.as_ref().map(Option::is_none) } /// Unwrap the individual fields. pub fn unwrap_or(self, other: Spec) -> Spec { Spec { x: self.x.unwrap_or(other.x), y: self.y.unwrap_or(other.y), } } } impl Spec { /// Select `t.x` if `self.x` is true and `f.x` otherwise and same for `y`. pub fn select(self, t: Spec, f: Spec) -> Spec { Spec { x: if self.x { t.x } else { f.x }, y: if self.y { t.y } else { f.y }, } } } impl Not for Spec { type Output = Self; fn not(self) -> Self::Output { Self { x: !self.x, y: !self.y } } } impl BitOr for Spec { type Output = Self; fn bitor(self, rhs: Self) -> Self::Output { Self { x: self.x | rhs.x, y: self.y | rhs.y } } } impl BitOr for Spec { type Output = Self; fn bitor(self, rhs: bool) -> Self::Output { Self { x: self.x | rhs, y: self.y | rhs } } } impl BitAnd for Spec { type Output = Self; fn bitand(self, rhs: Self) -> Self::Output { Self { x: self.x & rhs.x, y: self.y & rhs.y } } } impl BitAnd for Spec { type Output = Self; fn bitand(self, rhs: bool) -> Self::Output { Self { x: self.x & rhs, y: self.y & rhs } } } impl BitOrAssign for Spec { fn bitor_assign(&mut self, rhs: Self) { self.x |= rhs.x; self.y |= rhs.y; } } impl BitAndAssign for Spec { fn bitand_assign(&mut self, rhs: Self) { self.x &= rhs.x; self.y &= rhs.y; } }