diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-11-26 16:32:06 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-11-26 16:32:06 +0100 |
| commit | 3a15922d2ffc041c3523edb479f008a9034fd400 (patch) | |
| tree | 988fe103c0752696c1fade2123142a8db5361ab7 /src/geom/spec.rs | |
| parent | 393d74f9bb0d4c71a69108d5be261103c39f47f3 (diff) | |
X/Y abstractions
Diffstat (limited to 'src/geom/spec.rs')
| -rw-r--r-- | src/geom/spec.rs | 219 |
1 files changed, 181 insertions, 38 deletions
diff --git a/src/geom/spec.rs b/src/geom/spec.rs index 608643d8..640d6231 100644 --- a/src/geom/spec.rs +++ b/src/geom/spec.rs @@ -1,7 +1,10 @@ +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)] +#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct Spec<T> { /// The horizontal component. pub x: T, @@ -31,9 +34,18 @@ impl<T> Spec<T> { Spec { x: f(self.x), y: f(self.y) } } + /// Convert from `&Spec<T>` to `Spec<&T>`. + pub fn as_ref(&self) -> Spec<&T> { + Spec { x: &self.x, y: &self.y } + } + + /// Convert from `&mut Spec<T>` 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<U>(self, other: impl Into<Spec<U>>) -> Spec<(T, U)> { - let other = other.into(); + pub fn zip<U>(self, other: Spec<U>) -> Spec<(T, U)> { Spec { x: (self.x, other.x), y: (self.y, other.y), @@ -56,6 +68,14 @@ impl<T> Spec<T> { f(&self.x) && f(&self.y) } + /// Filter the individual fields with a mask. + pub fn filter(self, mask: Spec<bool>) -> Spec<Option<T>> { + 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<T> { match main { @@ -65,39 +85,6 @@ impl<T> Spec<T> { } } -impl From<Size> for Spec<Length> { - fn from(size: Size) -> Self { - size.to_spec() - } -} - -impl Spec<Length> { - /// The zero value. - pub fn zero() -> Self { - Self { x: Length::zero(), y: Length::zero() } - } - - /// Convert to a point. - pub fn to_point(self) -> Point { - Point::new(self.x, self.y) - } - - /// Convert to a size. - pub fn to_size(self) -> Size { - Size::new(self.x, self.y) - } -} - -impl<T> Spec<Option<T>> { - /// Unwrap the individual fields. - pub fn unwrap_or(self, other: Spec<T>) -> Spec<T> { - Spec { - x: self.x.unwrap_or(other.x), - y: self.y.unwrap_or(other.y), - } - } -} - impl<T> Get<SpecAxis> for Spec<T> { type Component = T; @@ -116,9 +103,20 @@ impl<T> Get<SpecAxis> for Spec<T> { } } -impl<T: Debug> Debug for Spec<T> { +impl<T> Debug for Spec<T> +where + T: Debug + 'static, +{ fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "Spec({:?}, {:?})", self.x, self.y) + if let Spec { x: Some(x), y: Some(y) } = + self.as_ref().map(|v| (v as &dyn Any).downcast_ref::<Align>()) + { + write!(f, "{:?}-{:?}", x, y) + } else if (&self.x as &dyn Any).is::<Length>() { + write!(f, "Size({:?}, {:?})", self.x, self.y) + } else { + write!(f, "Spec({:?}, {:?})", self.x, self.y) + } } } @@ -159,3 +157,148 @@ impl Debug for SpecAxis { }) } } + +/// A size in 2D. +pub type Size = Spec<Length>; + +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 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<f64> for Size { + type Output = Self; + + fn mul(self, other: f64) -> Self { + Self { x: self.x * other, y: self.y * other } + } +} + +impl Mul<Size> for f64 { + type Output = Size; + + fn mul(self, other: Size) -> Size { + other * self + } +} + +impl Div<f64> 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<T> Spec<Option<T>> { + /// Whether the individual fields are some. + pub fn map_is_some(&self) -> Spec<bool> { + self.as_ref().map(Option::is_some) + } + + /// Whether the individual fields are none. + pub fn map_is_none(&self) -> Spec<bool> { + self.as_ref().map(Option::is_none) + } + + /// Unwrap the individual fields. + pub fn unwrap_or(self, other: Spec<T>) -> Spec<T> { + Spec { + x: self.x.unwrap_or(other.x), + y: self.y.unwrap_or(other.y), + } + } +} + +impl Spec<bool> { + /// Select `t.x` if `self.x` is true and `f.x` otherwise and same for `y`. + pub fn select<T>(self, t: Spec<T>, f: Spec<T>) -> Spec<T> { + Spec { + x: if self.x { t.x } else { f.x }, + y: if self.y { t.y } else { f.y }, + } + } +} + +impl Not for Spec<bool> { + type Output = Self; + + fn not(self) -> Self::Output { + Self { x: !self.x, y: !self.y } + } +} + +impl BitOr for Spec<bool> { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self { x: self.x | rhs.x, y: self.y | rhs.y } + } +} + +impl BitAnd for Spec<bool> { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + Self { x: self.x & rhs.x, y: self.y & rhs.y } + } +} + +impl BitOrAssign for Spec<bool> { + fn bitor_assign(&mut self, rhs: Self) { + self.x |= rhs.x; + self.y |= rhs.y; + } +} + +impl BitAndAssign for Spec<bool> { + fn bitand_assign(&mut self, rhs: Self) { + self.x &= rhs.x; + self.y &= rhs.y; + } +} |
