use std::{
cmp::{Eq, PartialEq},
fmt,
hash::Hash,
iter::Sum,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use crate::prelude::{One, Zero};
#[repr(C)]
pub struct Size2D<T> {
pub width: T,
pub height: T,
}
impl<T: Copy> Copy for Size2D<T> {}
impl<T: Clone> Clone for Size2D<T> {
fn clone(&self) -> Self {
Size2D {
width: self.width.clone(),
height: self.height.clone(),
}
}
}
#[cfg(feature = "serde")]
impl<'de, T> serde::Deserialize<'de> for Size2D<T>
where
T: serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let (width, height) = serde::Deserialize::deserialize(deserializer)?;
Ok(Size2D {
width,
height,
_unit: PhantomData,
})
}
}
#[cfg(feature = "serde")]
impl<T> serde::Serialize for Size2D<T>
where
T: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(&self.width, &self.height).serialize(serializer)
}
}
#[cfg(feature = "arbitrary")]
impl<'a, T> arbitrary::Arbitrary<'a> for Size2D<T>
where
T: arbitrary::Arbitrary<'a>,
{
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let (width, height) = arbitrary::Arbitrary::arbitrary(u)?;
Ok(Size2D {
width,
height,
_unit: PhantomData,
})
}
}
impl<T> Eq for Size2D<T> where T: Eq {}
impl<T> PartialEq for Size2D<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.width == other.width && self.height == other.height
}
}
impl<T> Hash for Size2D<T>
where
T: Hash,
{
fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
self.width.hash(h);
self.height.hash(h);
}
}
impl<T: fmt::Debug> fmt::Debug for Size2D<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.width, f)?;
write!(f, "x")?;
fmt::Debug::fmt(&self.height, f)
}
}
impl<T: Default> Default for Size2D<T> {
fn default() -> Self {
Size2D::new(Default::default(), Default::default())
}
}
impl<T> Size2D<T> {
#[inline]
pub fn zero() -> Self
where
T: Zero,
{
Size2D::new(Zero::zero(), Zero::zero())
}
#[inline]
pub const fn new(width: T, height: T) -> Self {
Size2D { width, height }
}
#[inline]
pub fn splat(v: T) -> Self
where
T: Clone,
{
Size2D {
width: v.clone(),
height: v,
}
}
#[inline]
pub fn from_untyped(p: Size2D<T>) -> Self {
Size2D::new(p.width, p.height)
}
}
impl<T: Copy> Size2D<T> {
#[inline]
pub fn to_array(self) -> [T; 2] {
[self.width, self.height]
}
#[inline]
pub fn to_tuple(self) -> (T, T) {
(self.width, self.height)
}
pub fn area(self) -> T::Output
where
T: Mul,
{
self.width * self.height
}
#[inline]
pub fn lerp(self, other: Self, t: T) -> Self
where
T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
{
let one_t = T::one() - t;
self * one_t + other * t
}
}
impl<T: Zero> Zero for Size2D<T> {
#[inline]
fn zero() -> Self {
Size2D::new(Zero::zero(), Zero::zero())
}
}
impl<T: Neg> Neg for Size2D<T> {
type Output = Size2D<T::Output>;
#[inline]
fn neg(self) -> Self::Output {
Size2D::new(-self.width, -self.height)
}
}
impl<T: Add> Add for Size2D<T> {
type Output = Size2D<T::Output>;
#[inline]
fn add(self, other: Self) -> Self::Output {
Size2D::new(self.width + other.width, self.height + other.height)
}
}
impl<T: Copy + Add<T, Output = T>> Add<&Self> for Size2D<T> {
type Output = Self;
fn add(self, other: &Self) -> Self {
Size2D::new(self.width + other.width, self.height + other.height)
}
}
impl<T: Add<Output = T> + Zero> Sum for Size2D<T> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::zero(), Add::add)
}
}
impl<T: AddAssign> AddAssign for Size2D<T> {
#[inline]
fn add_assign(&mut self, other: Self) {
self.width += other.width;
self.height += other.height;
}
}
impl<T: Sub> Sub for Size2D<T> {
type Output = Size2D<T::Output>;
#[inline]
fn sub(self, other: Self) -> Self::Output {
Size2D::new(self.width - other.width, self.height - other.height)
}
}
impl<T: SubAssign> SubAssign for Size2D<T> {
#[inline]
fn sub_assign(&mut self, other: Self) {
self.width -= other.width;
self.height -= other.height;
}
}
impl<T: Copy + Mul> Mul<T> for Size2D<T> {
type Output = Size2D<T::Output>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Size2D::new(self.width * scale, self.height * scale)
}
}
impl<T: Copy + MulAssign> MulAssign<T> for Size2D<T> {
#[inline]
fn mul_assign(&mut self, other: T) {
self.width *= other;
self.height *= other;
}
}
impl<T: Copy + Div> Div<T> for Size2D<T> {
type Output = Size2D<T::Output>;
#[inline]
fn div(self, scale: T) -> Self::Output {
Size2D::new(self.width / scale, self.height / scale)
}
}
impl<T: Copy + DivAssign> DivAssign<T> for Size2D<T> {
#[inline]
fn div_assign(&mut self, other: T) {
self.width /= other;
self.height /= other;
}
}
#[inline]
pub const fn size2<T>(w: T, h: T) -> Size2D<T> {
Size2D::new(w, h)
}
#[cfg(feature = "mint")]
impl<T> From<mint::Vector2<T>> for Size2D<T> {
#[inline]
fn from(v: mint::Vector2<T>) -> Self {
Size2D {
width: v.x,
height: v.y,
_unit: PhantomData,
}
}
}
#[cfg(feature = "mint")]
impl<T> Into<mint::Vector2<T>> for Size2D<T> {
#[inline]
fn into(self) -> mint::Vector2<T> {
mint::Vector2 {
x: self.width,
y: self.height,
}
}
}
impl<T> Into<[T; 2]> for Size2D<T> {
#[inline]
fn into(self) -> [T; 2] {
[self.width, self.height]
}
}
impl<T> From<[T; 2]> for Size2D<T> {
#[inline]
fn from([w, h]: [T; 2]) -> Self {
size2(w, h)
}
}
impl<T> Into<(T, T)> for Size2D<T> {
#[inline]
fn into(self) -> (T, T) {
(self.width, self.height)
}
}
impl<T> From<(T, T)> for Size2D<T> {
#[inline]
fn from(tuple: (T, T)) -> Self {
size2(tuple.0, tuple.1)
}
}
#[cfg(test)]
mod size2d {
use crate::foundation::Size2D;
#[cfg(feature = "mint")]
use mint;
#[test]
pub fn test_area() {
let p = Size2D::new(1.5, 2.0);
assert_eq!(p.area(), 3.0);
}
#[cfg(feature = "mint")]
#[test]
pub fn test_mint() {
let s1 = Size2D::new(1.0, 2.0);
let sm: mint::Vector2<_> = s1.into();
let s2 = Size2D::from(sm);
assert_eq!(s1, s2);
}
mod ops {
use crate::foundation::Size2D;
#[test]
pub fn test_neg() {
assert_eq!(-Size2D::new(1.0, 2.0), Size2D::new(-1.0, -2.0));
assert_eq!(-Size2D::new(0.0, 0.0), Size2D::new(-0.0, -0.0));
assert_eq!(-Size2D::new(-1.0, -2.0), Size2D::new(1.0, 2.0));
}
#[test]
pub fn test_add() {
let s1 = Size2D::new(1.0, 2.0);
let s2 = Size2D::new(3.0, 4.0);
assert_eq!(s1 + s2, Size2D::new(4.0, 6.0));
assert_eq!(s1 + &s2, Size2D::new(4.0, 6.0));
let s1 = Size2D::new(1.0, 2.0);
let s2 = Size2D::new(0.0, 0.0);
assert_eq!(s1 + s2, Size2D::new(1.0, 2.0));
assert_eq!(s1 + &s2, Size2D::new(1.0, 2.0));
let s1 = Size2D::new(1.0, 2.0);
let s2 = Size2D::new(-3.0, -4.0);
assert_eq!(s1 + s2, Size2D::new(-2.0, -2.0));
assert_eq!(s1 + &s2, Size2D::new(-2.0, -2.0));
let s1 = Size2D::new(0.0, 0.0);
let s2 = Size2D::new(0.0, 0.0);
assert_eq!(s1 + s2, Size2D::new(0.0, 0.0));
assert_eq!(s1 + &s2, Size2D::new(0.0, 0.0));
}
#[test]
pub fn test_add_assign() {
let mut s = Size2D::new(1.0, 2.0);
s += Size2D::new(3.0, 4.0);
assert_eq!(s, Size2D::new(4.0, 6.0));
let mut s = Size2D::new(1.0, 2.0);
s += Size2D::new(0.0, 0.0);
assert_eq!(s, Size2D::new(1.0, 2.0));
let mut s = Size2D::new(1.0, 2.0);
s += Size2D::new(-3.0, -4.0);
assert_eq!(s, Size2D::new(-2.0, -2.0));
let mut s = Size2D::new(0.0, 0.0);
s += Size2D::new(0.0, 0.0);
assert_eq!(s, Size2D::new(0.0, 0.0));
}
#[test]
pub fn test_sub() {
let s1 = Size2D::new(1.0, 2.0);
let s2 = Size2D::new(3.0, 4.0);
assert_eq!(s1 - s2, Size2D::new(-2.0, -2.0));
let s1 = Size2D::new(1.0, 2.0);
let s2 = Size2D::new(0.0, 0.0);
assert_eq!(s1 - s2, Size2D::new(1.0, 2.0));
let s1 = Size2D::new(1.0, 2.0);
let s2 = Size2D::new(-3.0, -4.0);
assert_eq!(s1 - s2, Size2D::new(4.0, 6.0));
let s1 = Size2D::new(0.0, 0.0);
let s2 = Size2D::new(0.0, 0.0);
assert_eq!(s1 - s2, Size2D::new(0.0, 0.0));
}
#[test]
pub fn test_sub_assign() {
let mut s = Size2D::new(1.0, 2.0);
s -= Size2D::new(3.0, 4.0);
assert_eq!(s, Size2D::new(-2.0, -2.0));
let mut s = Size2D::new(1.0, 2.0);
s -= Size2D::new(0.0, 0.0);
assert_eq!(s, Size2D::new(1.0, 2.0));
let mut s = Size2D::new(1.0, 2.0);
s -= Size2D::new(-3.0, -4.0);
assert_eq!(s, Size2D::new(4.0, 6.0));
let mut s = Size2D::new(0.0, 0.0);
s -= Size2D::new(0.0, 0.0);
assert_eq!(s, Size2D::new(0.0, 0.0));
}
#[test]
pub fn test_mul_scalar() {
let s1: Size2D<f32> = Size2D::new(3.0, 5.0);
let result = s1 * 5.0;
assert_eq!(result, Size2D::new(15.0, 25.0));
}
#[test]
pub fn test_mul_assign_scalar() {
let mut s1 = Size2D::new(3.0, 5.0);
s1 *= 5.0;
assert_eq!(s1, Size2D::new(15.0, 25.0));
}
#[test]
pub fn test_div_scalar() {
let s1: Size2D<f32> = Size2D::new(15.0, 25.0);
let result = s1 / 5.0;
assert_eq!(result, Size2D::new(3.0, 5.0));
}
#[test]
pub fn test_div_assign_scalar() {
let mut s1: Size2D<f32> = Size2D::new(15.0, 25.0);
s1 /= 5.0;
assert_eq!(s1, Size2D::new(3.0, 5.0));
}
}
}