use super::{One, Zero};
use core::cmp::{Eq, PartialEq};
use core::fmt;
use core::hash::Hash;
use core::iter::Sum;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[repr(C)]
pub struct Size3D<T> {
pub width: T,
pub height: T,
pub depth: T,
}
impl<T: Copy> Copy for Size3D<T> {}
impl<T: Clone> Clone for Size3D<T> {
fn clone(&self) -> Self {
Size3D {
width: self.width.clone(),
height: self.height.clone(),
depth: self.depth.clone(),
}
}
}
#[cfg(feature = "serde")]
impl<'de, T> serde::Deserialize<'de> for Size3D<T>
where
T: serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let (width, height, depth) = serde::Deserialize::deserialize(deserializer)?;
Ok(Size3D {
width,
height,
depth,
_unit: PhantomData,
})
}
}
#[cfg(feature = "serde")]
impl<T> serde::Serialize for Size3D<T>
where
T: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(&self.width, &self.height, &self.depth).serialize(serializer)
}
}
impl<T> Eq for Size3D<T> where T: Eq {}
impl<T> PartialEq for Size3D<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.width == other.width && self.height == other.height && self.depth == other.depth
}
}
impl<T> Hash for Size3D<T>
where
T: Hash,
{
fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
self.width.hash(h);
self.height.hash(h);
self.depth.hash(h);
}
}
impl<T: fmt::Debug> fmt::Debug for Size3D<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)?;
write!(f, "x")?;
fmt::Debug::fmt(&self.depth, f)
}
}
impl<T: Default> Default for Size3D<T> {
fn default() -> Self {
Size3D::new(Default::default(), Default::default(), Default::default())
}
}
impl<T> Size3D<T> {
pub fn zero() -> Self
where
T: Zero,
{
Size3D::new(Zero::zero(), Zero::zero(), Zero::zero())
}
#[inline]
pub const fn new(width: T, height: T, depth: T) -> Self {
Size3D {
width,
height,
depth,
}
}
#[inline]
pub fn splat(v: T) -> Self
where
T: Clone,
{
Size3D {
width: v.clone(),
height: v.clone(),
depth: v,
}
}
#[inline]
pub fn from_untyped(p: Size3D<T>) -> Self {
Size3D::new(p.width, p.height, p.depth)
}
}
impl<T: Copy> Size3D<T> {
#[inline]
pub fn to_array(self) -> [T; 3] {
[self.width, self.height, self.depth]
}
#[inline]
pub fn to_tuple(self) -> (T, T, T) {
(self.width, self.height, self.depth)
}
pub fn volume(self) -> T
where
T: Mul<Output = T>,
{
self.width * self.height * self.depth
}
#[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 Size3D<T> {
#[inline]
fn zero() -> Self {
Size3D::new(Zero::zero(), Zero::zero(), Zero::zero())
}
}
impl<T: Neg> Neg for Size3D<T> {
type Output = Size3D<T::Output>;
#[inline]
fn neg(self) -> Self::Output {
Size3D::new(-self.width, -self.height, -self.depth)
}
}
impl<T: Add> Add for Size3D<T> {
type Output = Size3D<T::Output>;
#[inline]
fn add(self, other: Self) -> Self::Output {
Size3D::new(
self.width + other.width,
self.height + other.height,
self.depth + other.depth,
)
}
}
impl<T: Copy + Add<T, Output = T>> Add<&Self> for Size3D<T> {
type Output = Self;
fn add(self, other: &Self) -> Self {
Size3D::new(
self.width + other.width,
self.height + other.height,
self.depth + other.depth,
)
}
}
impl<T: Add<Output = T> + Zero> Sum for Size3D<T> {
fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
iter.fold(Self::zero(), Add::add)
}
}
impl<T: AddAssign> AddAssign for Size3D<T> {
#[inline]
fn add_assign(&mut self, other: Self) {
self.width += other.width;
self.height += other.height;
self.depth += other.depth;
}
}
impl<T: Sub> Sub for Size3D<T> {
type Output = Size3D<T::Output>;
#[inline]
fn sub(self, other: Self) -> Self::Output {
Size3D::new(
self.width - other.width,
self.height - other.height,
self.depth - other.depth,
)
}
}
impl<T: SubAssign> SubAssign for Size3D<T> {
#[inline]
fn sub_assign(&mut self, other: Self) {
self.width -= other.width;
self.height -= other.height;
self.depth -= other.depth;
}
}
impl<T: Copy + Mul> Mul<T> for Size3D<T> {
type Output = Size3D<T::Output>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Size3D::new(
self.width * scale,
self.height * scale,
self.depth * scale,
)
}
}
impl<T: Copy + MulAssign> MulAssign<T> for Size3D<T> {
#[inline]
fn mul_assign(&mut self, other: T) {
self.width *= other;
self.height *= other;
self.depth *= other;
}
}
impl<T: Copy + Div> Div<T> for Size3D<T> {
type Output = Size3D<T::Output>;
#[inline]
fn div(self, scale: T) -> Self::Output {
Size3D::new(
self.width / scale,
self.height / scale,
self.depth / scale,
)
}
}
impl<T: Copy + DivAssign> DivAssign<T> for Size3D<T> {
#[inline]
fn div_assign(&mut self, other: T) {
self.width /= other;
self.height /= other;
self.depth /= other;
}
}
#[cfg(feature = "mint")]
impl<T> From<mint::Vector3<T>> for Size3D<T> {
#[inline]
fn from(v: mint::Vector3<T>) -> Self {
size3(v.x, v.y, v.z)
}
}
#[cfg(feature = "mint")]
impl<T> Into<mint::Vector3<T>> for Size3D<T> {
#[inline]
fn into(self) -> mint::Vector3<T> {
mint::Vector3 {
x: self.width,
y: self.height,
z: self.depth,
}
}
}
impl<T> Into<[T; 3]> for Size3D<T> {
#[inline]
fn into(self) -> [T; 3] {
[self.width, self.height, self.depth]
}
}
impl<T> From<[T; 3]> for Size3D<T> {
#[inline]
fn from([w, h, d]: [T; 3]) -> Self {
size3(w, h, d)
}
}
impl<T> Into<(T, T, T)> for Size3D<T> {
#[inline]
fn into(self) -> (T, T, T) {
(self.width, self.height, self.depth)
}
}
impl<T> From<(T, T, T)> for Size3D<T> {
#[inline]
fn from(tuple: (T, T, T)) -> Self {
size3(tuple.0, tuple.1, tuple.2)
}
}
#[inline]
pub const fn size3<T>(w: T, h: T, d: T) -> Size3D<T> {
Size3D::new(w, h, d)
}
#[cfg(test)]
mod size3d {
mod ops {
use crate::Size3D;
#[test]
pub fn test_neg() {
assert_eq!(-Size3D::new(1.0, 2.0, 3.0), Size3D::new(-1.0, -2.0, -3.0));
assert_eq!(-Size3D::new(0.0, 0.0, 0.0), Size3D::new(-0.0, -0.0, -0.0));
assert_eq!(-Size3D::new(-1.0, -2.0, -3.0), Size3D::new(1.0, 2.0, 3.0));
}
#[test]
pub fn test_add() {
let s1 = Size3D::new(1.0, 2.0, 3.0);
let s2 = Size3D::new(4.0, 5.0, 6.0);
assert_eq!(s1 + s2, Size3D::new(5.0, 7.0, 9.0));
assert_eq!(s1 + &s2, Size3D::new(5.0, 7.0, 9.0));
let s1 = Size3D::new(1.0, 2.0, 3.0);
let s2 = Size3D::new(0.0, 0.0, 0.0);
assert_eq!(s1 + s2, Size3D::new(1.0, 2.0, 3.0));
assert_eq!(s1 + &s2, Size3D::new(1.0, 2.0, 3.0));
let s1 = Size3D::new(1.0, 2.0, 3.0);
let s2 = Size3D::new(-4.0, -5.0, -6.0);
assert_eq!(s1 + s2, Size3D::new(-3.0, -3.0, -3.0));
assert_eq!(s1 + &s2, Size3D::new(-3.0, -3.0, -3.0));
let s1 = Size3D::new(0.0, 0.0, 0.0);
let s2 = Size3D::new(0.0, 0.0, 0.0);
assert_eq!(s1 + s2, Size3D::new(0.0, 0.0, 0.0));
assert_eq!(s1 + &s2, Size3D::new(0.0, 0.0, 0.0));
}
#[test]
pub fn test_add_assign() {
let mut s = Size3D::new(1.0, 2.0, 3.0);
s += Size3D::new(4.0, 5.0, 6.0);
assert_eq!(s, Size3D::new(5.0, 7.0, 9.0));
let mut s = Size3D::new(1.0, 2.0, 3.0);
s += Size3D::new(0.0, 0.0, 0.0);
assert_eq!(s, Size3D::new(1.0, 2.0, 3.0));
let mut s = Size3D::new(1.0, 2.0, 3.0);
s += Size3D::new(-4.0, -5.0, -6.0);
assert_eq!(s, Size3D::new(-3.0, -3.0, -3.0));
let mut s = Size3D::new(0.0, 0.0, 0.0);
s += Size3D::new(0.0, 0.0, 0.0);
assert_eq!(s, Size3D::new(0.0, 0.0, 0.0));
}
#[test]
pub fn test_sub() {
let s1 = Size3D::new(1.0, 2.0, 3.0);
let s2 = Size3D::new(4.0, 5.0, 6.0);
assert_eq!(s1 - s2, Size3D::new(-3.0, -3.0, -3.0));
let s1 = Size3D::new(1.0, 2.0, 3.0);
let s2 = Size3D::new(0.0, 0.0, 0.0);
assert_eq!(s1 - s2, Size3D::new(1.0, 2.0, 3.0));
let s1 = Size3D::new(1.0, 2.0, 3.0);
let s2 = Size3D::new(-4.0, -5.0, -6.0);
assert_eq!(s1 - s2, Size3D::new(5.0, 7.0, 9.0));
let s1 = Size3D::new(0.0, 0.0, 0.0);
let s2 = Size3D::new(0.0, 0.0, 0.0);
assert_eq!(s1 - s2, Size3D::new(0.0, 0.0, 0.0));
}
#[test]
pub fn test_sub_assign() {
let mut s = Size3D::new(1.0, 2.0, 3.0);
s -= Size3D::new(4.0, 5.0, 6.0);
assert_eq!(s, Size3D::new(-3.0, -3.0, -3.0));
let mut s = Size3D::new(1.0, 2.0, 3.0);
s -= Size3D::new(0.0, 0.0, 0.0);
assert_eq!(s, Size3D::new(1.0, 2.0, 3.0));
let mut s = Size3D::new(1.0, 2.0, 3.0);
s -= Size3D::new(-4.0, -5.0, -6.0);
assert_eq!(s, Size3D::new(5.0, 7.0, 9.0));
let mut s = Size3D::new(0.0, 0.0, 0.0);
s -= Size3D::new(0.0, 0.0, 0.0);
assert_eq!(s, Size3D::new(0.0, 0.0, 0.0));
}
#[test]
pub fn test_mul_scalar() {
let s1: Size3D<f32> = Size3D::new(3.0, 5.0, 7.0);
let result = s1 * 5.0;
assert_eq!(result, Size3D::new(15.0, 25.0, 35.0));
}
#[test]
pub fn test_mul_assign_scalar() {
let mut s1: Size3D<f32> = Size3D::new(3.0, 5.0, 7.0);
s1 *= 5.0;
assert_eq!(s1, Size3D::new(15.0, 25.0, 35.0));
}
#[test]
pub fn test_div_scalar() {
let s1: Size3D<f32> = Size3D::new(15.0, 25.0, 35.0);
let result = s1 / 5.0;
assert_eq!(result, Size3D::new(3.0, 5.0, 7.0));
}
#[test]
pub fn test_div_assign_scalar() {
let mut s1: Size3D<f32> = Size3D::new(15.0, 25.0, 35.0);
s1 /= 5.0;
assert_eq!(s1, Size3D::new(3.0, 5.0, 7.0));
}
}
}