euclid/
size.rs

1// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10use super::UnknownUnit;
11use crate::approxord::{max, min};
12use crate::length::Length;
13use crate::num::*;
14use crate::scale::Scale;
15use crate::vector::{vec2, BoolVector2D, Vector2D};
16use crate::vector::{vec3, BoolVector3D, Vector3D};
17#[cfg(feature = "mint")]
18use mint;
19
20use core::cmp::{Eq, PartialEq};
21use core::fmt;
22use core::hash::Hash;
23use core::marker::PhantomData;
24use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
25use num_traits::{NumCast, Signed};
26#[cfg(feature = "serde")]
27use serde;
28
29/// A 2d size tagged with a unit.
30#[repr(C)]
31pub struct Size2D<T, U> {
32    /// The extent of the element in the `U` units along the `x` axis (usually horizontal).
33    pub width: T,
34    /// The extent of the element in the `U` units along the `y` axis (usually vertical).
35    pub height: T,
36    #[doc(hidden)]
37    pub _unit: PhantomData<U>,
38}
39
40impl<T: Copy, U> Copy for Size2D<T, U> {}
41
42impl<T: Clone, U> Clone for Size2D<T, U> {
43    fn clone(&self) -> Self {
44        Size2D {
45            width: self.width.clone(),
46            height: self.height.clone(),
47            _unit: PhantomData,
48        }
49    }
50}
51
52#[cfg(feature = "serde")]
53impl<'de, T, U> serde::Deserialize<'de> for Size2D<T, U>
54where
55    T: serde::Deserialize<'de>,
56{
57    /// Deserializes 2d size from tuple of width and height.
58    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59    where
60        D: serde::Deserializer<'de>,
61    {
62        let (width, height) = serde::Deserialize::deserialize(deserializer)?;
63        Ok(Size2D {
64            width,
65            height,
66            _unit: PhantomData,
67        })
68    }
69}
70
71#[cfg(feature = "serde")]
72impl<T, U> serde::Serialize for Size2D<T, U>
73where
74    T: serde::Serialize,
75{
76    /// Serializes 2d size to tuple of width and height.
77    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
78    where
79        S: serde::Serializer,
80    {
81        (&self.width, &self.height).serialize(serializer)
82    }
83}
84
85impl<T, U> Eq for Size2D<T, U> where T: Eq {}
86
87impl<T, U> PartialEq for Size2D<T, U>
88where
89    T: PartialEq,
90{
91    fn eq(&self, other: &Self) -> bool {
92        self.width == other.width && self.height == other.height
93    }
94}
95
96impl<T, U> Hash for Size2D<T, U>
97where
98    T: Hash,
99{
100    fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
101        self.width.hash(h);
102        self.height.hash(h);
103    }
104}
105
106impl<T: fmt::Debug, U> fmt::Debug for Size2D<T, U> {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        fmt::Debug::fmt(&self.width, f)?;
109        write!(f, "x")?;
110        fmt::Debug::fmt(&self.height, f)
111    }
112}
113
114impl<T: Default, U> Default for Size2D<T, U> {
115    fn default() -> Self {
116        Size2D::new(Default::default(), Default::default())
117    }
118}
119
120impl<T, U> Size2D<T, U> {
121    /// The same as [`Zero::zero()`] but available without importing trait.
122    ///
123    /// [`Zero::zero()`]: ./num/trait.Zero.html#tymethod.zero
124    #[inline]
125    pub fn zero() -> Self
126    where
127        T: Zero,
128    {
129        Size2D::new(Zero::zero(), Zero::zero())
130    }
131
132    /// Constructor taking scalar values.
133    #[inline]
134    pub const fn new(width: T, height: T) -> Self {
135        Size2D {
136            width,
137            height,
138            _unit: PhantomData,
139        }
140    }
141    /// Constructor taking scalar strongly typed lengths.
142    #[inline]
143    pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> Self {
144        Size2D::new(width.0, height.0)
145    }
146
147    /// Tag a unitless value with units.
148    #[inline]
149    pub fn from_untyped(p: Size2D<T, UnknownUnit>) -> Self {
150        Size2D::new(p.width, p.height)
151    }
152}
153
154impl<T: Copy, U> Size2D<T, U> {
155    /// Return this size as an array of two elements (width, then height).
156    #[inline]
157    pub fn to_array(self) -> [T; 2] {
158        [self.width, self.height]
159    }
160
161    /// Return this size as a tuple of two elements (width, then height).
162    #[inline]
163    pub fn to_tuple(self) -> (T, T) {
164        (self.width, self.height)
165    }
166
167    /// Return this size as a vector with width and height.
168    #[inline]
169    pub fn to_vector(self) -> Vector2D<T, U> {
170        vec2(self.width, self.height)
171    }
172
173    /// Drop the units, preserving only the numeric value.
174    #[inline]
175    pub fn to_untyped(self) -> Size2D<T, UnknownUnit> {
176        self.cast_unit()
177    }
178
179    /// Cast the unit
180    #[inline]
181    pub fn cast_unit<V>(self) -> Size2D<T, V> {
182        Size2D::new(self.width, self.height)
183    }
184
185    /// Rounds each component to the nearest integer value.
186    ///
187    /// This behavior is preserved for negative values (unlike the basic cast).
188    ///
189    /// ```rust
190    /// # use euclid::size2;
191    /// enum Mm {}
192    ///
193    /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).round(), size2::<_, Mm>(0.0, -1.0))
194    /// ```
195    #[inline]
196    #[must_use]
197    pub fn round(self) -> Self
198    where
199        T: Round,
200    {
201        Size2D::new(self.width.round(), self.height.round())
202    }
203
204    /// Rounds each component to the smallest integer equal or greater than the original value.
205    ///
206    /// This behavior is preserved for negative values (unlike the basic cast).
207    ///
208    /// ```rust
209    /// # use euclid::size2;
210    /// enum Mm {}
211    ///
212    /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).ceil(), size2::<_, Mm>(0.0, 0.0))
213    /// ```
214    #[inline]
215    #[must_use]
216    pub fn ceil(self) -> Self
217    where
218        T: Ceil,
219    {
220        Size2D::new(self.width.ceil(), self.height.ceil())
221    }
222
223    /// Rounds each component to the biggest integer equal or lower than the original value.
224    ///
225    /// This behavior is preserved for negative values (unlike the basic cast).
226    ///
227    /// ```rust
228    /// # use euclid::size2;
229    /// enum Mm {}
230    ///
231    /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).floor(), size2::<_, Mm>(-1.0, -1.0))
232    /// ```
233    #[inline]
234    #[must_use]
235    pub fn floor(self) -> Self
236    where
237        T: Floor,
238    {
239        Size2D::new(self.width.floor(), self.height.floor())
240    }
241
242    /// Returns result of multiplication of both components
243    pub fn area(self) -> T::Output
244    where
245        T: Mul,
246    {
247        self.width * self.height
248    }
249
250    /// Linearly interpolate each component between this size and another size.
251    ///
252    /// # Example
253    ///
254    /// ```rust
255    /// use euclid::size2;
256    /// use euclid::default::Size2D;
257    ///
258    /// let from: Size2D<_> = size2(0.0, 10.0);
259    /// let to:  Size2D<_> = size2(8.0, -4.0);
260    ///
261    /// assert_eq!(from.lerp(to, -1.0), size2(-8.0,  24.0));
262    /// assert_eq!(from.lerp(to,  0.0), size2( 0.0,  10.0));
263    /// assert_eq!(from.lerp(to,  0.5), size2( 4.0,   3.0));
264    /// assert_eq!(from.lerp(to,  1.0), size2( 8.0,  -4.0));
265    /// assert_eq!(from.lerp(to,  2.0), size2(16.0, -18.0));
266    /// ```
267    #[inline]
268    pub fn lerp(self, other: Self, t: T) -> Self
269    where
270        T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
271    {
272        let one_t = T::one() - t;
273        self * one_t + other * t
274    }
275}
276
277impl<T: NumCast + Copy, U> Size2D<T, U> {
278    /// Cast from one numeric representation to another, preserving the units.
279    ///
280    /// When casting from floating point to integer coordinates, the decimals are truncated
281    /// as one would expect from a simple cast, but this behavior does not always make sense
282    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
283    #[inline]
284    pub fn cast<NewT: NumCast>(self) -> Size2D<NewT, U> {
285        self.try_cast().unwrap()
286    }
287
288    /// Fallible cast from one numeric representation to another, preserving the units.
289    ///
290    /// When casting from floating point to integer coordinates, the decimals are truncated
291    /// as one would expect from a simple cast, but this behavior does not always make sense
292    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
293    pub fn try_cast<NewT: NumCast>(self) -> Option<Size2D<NewT, U>> {
294        match (NumCast::from(self.width), NumCast::from(self.height)) {
295            (Some(w), Some(h)) => Some(Size2D::new(w, h)),
296            _ => None,
297        }
298    }
299
300    // Convenience functions for common casts
301
302    /// Cast into an `f32` size.
303    #[inline]
304    pub fn to_f32(self) -> Size2D<f32, U> {
305        self.cast()
306    }
307
308    /// Cast into an `f64` size.
309    #[inline]
310    pub fn to_f64(self) -> Size2D<f64, U> {
311        self.cast()
312    }
313
314    /// Cast into an `uint` size, truncating decimals if any.
315    ///
316    /// When casting from floating point sizes, it is worth considering whether
317    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
318    /// the desired conversion behavior.
319    #[inline]
320    pub fn to_usize(self) -> Size2D<usize, U> {
321        self.cast()
322    }
323
324    /// Cast into an `u32` size, truncating decimals if any.
325    ///
326    /// When casting from floating point sizes, it is worth considering whether
327    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
328    /// the desired conversion behavior.
329    #[inline]
330    pub fn to_u32(self) -> Size2D<u32, U> {
331        self.cast()
332    }
333
334    /// Cast into an `u64` size, truncating decimals if any.
335    ///
336    /// When casting from floating point sizes, it is worth considering whether
337    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
338    /// the desired conversion behavior.
339    #[inline]
340    pub fn to_u64(self) -> Size2D<u64, U> {
341        self.cast()
342    }
343
344    /// Cast into an `i32` size, truncating decimals if any.
345    ///
346    /// When casting from floating point sizes, it is worth considering whether
347    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
348    /// the desired conversion behavior.
349    #[inline]
350    pub fn to_i32(self) -> Size2D<i32, U> {
351        self.cast()
352    }
353
354    /// Cast into an `i64` size, truncating decimals if any.
355    ///
356    /// When casting from floating point sizes, it is worth considering whether
357    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
358    /// the desired conversion behavior.
359    #[inline]
360    pub fn to_i64(self) -> Size2D<i64, U> {
361        self.cast()
362    }
363}
364
365impl<T: Signed, U> Size2D<T, U> {
366    /// Computes the absolute value of each component.
367    ///
368    /// For `f32` and `f64`, `NaN` will be returned for component if the component is `NaN`.
369    ///
370    /// For signed integers, `::MIN` will be returned for component if the component is `::MIN`.
371    pub fn abs(self) -> Self {
372        size2(self.width.abs(), self.height.abs())
373    }
374
375    /// Returns `true` if both components is positive and `false` any component is zero or negative.
376    pub fn is_positive(self) -> bool {
377        self.width.is_positive() && self.height.is_positive()
378    }
379}
380
381impl<T: PartialOrd, U> Size2D<T, U> {
382    /// Returns the size each component of which are minimum of this size and another.
383    #[inline]
384    pub fn min(self, other: Self) -> Self {
385        size2(min(self.width, other.width), min(self.height, other.height))
386    }
387
388    /// Returns the size each component of which are maximum of this size and another.
389    #[inline]
390    pub fn max(self, other: Self) -> Self {
391        size2(max(self.width, other.width), max(self.height, other.height))
392    }
393
394    /// Returns the size each component of which clamped by corresponding
395    /// components of `start` and `end`.
396    ///
397    /// Shortcut for `self.max(start).min(end)`.
398    #[inline]
399    pub fn clamp(self, start: Self, end: Self) -> Self
400    where
401        T: Copy,
402    {
403        self.max(start).min(end)
404    }
405
406    /// Returns vector with results of "greater then" operation on each component.
407    pub fn greater_than(self, other: Self) -> BoolVector2D {
408        BoolVector2D {
409            x: self.width > other.width,
410            y: self.height > other.height,
411        }
412    }
413
414    /// Returns vector with results of "lower then" operation on each component.
415    pub fn lower_than(self, other: Self) -> BoolVector2D {
416        BoolVector2D {
417            x: self.width < other.width,
418            y: self.height < other.height,
419        }
420    }
421
422    /// Returns `true` if any component of size is zero, negative, or NaN.
423    pub fn is_empty(self) -> bool
424    where
425        T: Zero,
426    {
427        let zero = T::zero();
428        // The condition is experessed this way so that we return true in
429        // the presence of NaN. 
430        !(self.width > zero && self.height > zero)
431    }
432}
433
434impl<T: PartialEq, U> Size2D<T, U> {
435    /// Returns vector with results of "equal" operation on each component.
436    pub fn equal(self, other: Self) -> BoolVector2D {
437        BoolVector2D {
438            x: self.width == other.width,
439            y: self.height == other.height,
440        }
441    }
442
443    /// Returns vector with results of "not equal" operation on each component.
444    pub fn not_equal(self, other: Self) -> BoolVector2D {
445        BoolVector2D {
446            x: self.width != other.width,
447            y: self.height != other.height,
448        }
449    }
450}
451
452impl<T: Round, U> Round for Size2D<T, U> {
453    /// See [`Size2D::round()`](#method.round).
454    #[inline]
455    fn round(self) -> Self {
456        self.round()
457    }
458}
459
460impl<T: Ceil, U> Ceil for Size2D<T, U> {
461    /// See [`Size2D::ceil()`](#method.ceil).
462    #[inline]
463    fn ceil(self) -> Self {
464        self.ceil()
465    }
466}
467
468impl<T: Floor, U> Floor for Size2D<T, U> {
469    /// See [`Size2D::floor()`](#method.floor).
470    #[inline]
471    fn floor(self) -> Self {
472        self.floor()
473    }
474}
475
476impl<T: Zero, U> Zero for Size2D<T, U> {
477    #[inline]
478    fn zero() -> Self {
479        Size2D::new(Zero::zero(), Zero::zero())
480    }
481}
482
483impl<T: Neg, U> Neg for Size2D<T, U> {
484    type Output = Size2D<T::Output, U>;
485
486    #[inline]
487    fn neg(self) -> Self::Output {
488        Size2D::new(-self.width, -self.height)
489    }
490}
491
492impl<T: Add, U> Add for Size2D<T, U> {
493    type Output = Size2D<T::Output, U>;
494
495    #[inline]
496    fn add(self, other: Self) -> Self::Output {
497        Size2D::new(self.width + other.width, self.height + other.height)
498    }
499}
500
501impl<T: AddAssign, U> AddAssign for Size2D<T, U> {
502    #[inline]
503    fn add_assign(&mut self, other: Self) {
504        self.width += other.width;
505        self.height += other.height;
506    }
507}
508
509impl<T: Sub, U> Sub for Size2D<T, U> {
510    type Output = Size2D<T::Output, U>;
511
512    #[inline]
513    fn sub(self, other: Self) -> Self::Output {
514        Size2D::new(self.width - other.width, self.height - other.height)
515    }
516}
517
518impl<T: SubAssign, U> SubAssign for Size2D<T, U> {
519    #[inline]
520    fn sub_assign(&mut self, other: Self) {
521        self.width -= other.width;
522        self.height -= other.height;
523    }
524}
525
526impl<T: Copy + Mul, U> Mul<T> for Size2D<T, U> {
527    type Output = Size2D<T::Output, U>;
528
529    #[inline]
530    fn mul(self, scale: T) -> Self::Output {
531        Size2D::new(self.width * scale, self.height * scale)
532    }
533}
534
535impl<T: Copy + MulAssign, U> MulAssign<T> for Size2D<T, U> {
536    #[inline]
537    fn mul_assign(&mut self, other: T) {
538        self.width *= other;
539        self.height *= other;
540    }
541}
542
543impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Size2D<T, U1> {
544    type Output = Size2D<T::Output, U2>;
545
546    #[inline]
547    fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
548        Size2D::new(self.width * scale.0, self.height * scale.0)
549    }
550}
551
552impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Size2D<T, U> {
553    #[inline]
554    fn mul_assign(&mut self, other: Scale<T, U, U>) {
555        *self *= other.0;
556    }
557}
558
559impl<T: Copy + Div, U> Div<T> for Size2D<T, U> {
560    type Output = Size2D<T::Output, U>;
561
562    #[inline]
563    fn div(self, scale: T) -> Self::Output {
564        Size2D::new(self.width / scale, self.height / scale)
565    }
566}
567
568impl<T: Copy + DivAssign, U> DivAssign<T> for Size2D<T, U> {
569    #[inline]
570    fn div_assign(&mut self, other: T) {
571        self.width /= other;
572        self.height /= other;
573    }
574}
575
576impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Size2D<T, U2> {
577    type Output = Size2D<T::Output, U1>;
578
579    #[inline]
580    fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
581        Size2D::new(self.width / scale.0, self.height / scale.0)
582    }
583}
584
585impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Size2D<T, U> {
586    #[inline]
587    fn div_assign(&mut self, other: Scale<T, U, U>) {
588        *self /= other.0;
589    }
590}
591
592/// Shorthand for `Size2D::new(w, h)`.
593#[inline]
594pub const fn size2<T, U>(w: T, h: T) -> Size2D<T, U> {
595    Size2D::new(w, h)
596}
597
598#[cfg(feature = "mint")]
599impl<T, U> From<mint::Vector2<T>> for Size2D<T, U> {
600    #[inline]
601    fn from(v: mint::Vector2<T>) -> Self {
602        Size2D {
603            width: v.x,
604            height: v.y,
605            _unit: PhantomData,
606        }
607    }
608}
609#[cfg(feature = "mint")]
610impl<T, U> Into<mint::Vector2<T>> for Size2D<T, U> {
611    #[inline]
612    fn into(self) -> mint::Vector2<T> {
613        mint::Vector2 {
614            x: self.width,
615            y: self.height,
616        }
617    }
618}
619
620impl<T, U> From<Vector2D<T, U>> for Size2D<T, U> {
621    #[inline]
622    fn from(v: Vector2D<T, U>) -> Self {
623        size2(v.x, v.y)
624    }
625}
626
627impl<T, U> Into<[T; 2]> for Size2D<T, U> {
628    #[inline]
629    fn into(self) -> [T; 2] {
630        [self.width, self.height]
631    }
632}
633
634impl<T, U> From<[T; 2]> for Size2D<T, U> {
635    #[inline]
636    fn from([w, h]: [T; 2]) -> Self {
637        size2(w, h)
638    }
639}
640
641impl<T, U> Into<(T, T)> for Size2D<T, U> {
642    #[inline]
643    fn into(self) -> (T, T) {
644        (self.width, self.height)
645    }
646}
647
648impl<T, U> From<(T, T)> for Size2D<T, U> {
649    #[inline]
650    fn from(tuple: (T, T)) -> Self {
651        size2(tuple.0, tuple.1)
652    }
653}
654
655#[cfg(test)]
656mod size2d {
657    use crate::default::Size2D;
658    #[cfg(feature = "mint")]
659    use mint;
660
661    #[test]
662    pub fn test_area() {
663        let p = Size2D::new(1.5, 2.0);
664        assert_eq!(p.area(), 3.0);
665    }
666
667    #[cfg(feature = "mint")]
668    #[test]
669    pub fn test_mint() {
670        let s1 = Size2D::new(1.0, 2.0);
671        let sm: mint::Vector2<_> = s1.into();
672        let s2 = Size2D::from(sm);
673
674        assert_eq!(s1, s2);
675    }
676
677    mod ops {
678        use crate::default::Size2D;
679        use crate::scale::Scale;
680
681        pub enum Mm {}
682        pub enum Cm {}
683
684        pub type Size2DMm<T> = crate::Size2D<T, Mm>;
685        pub type Size2DCm<T> = crate::Size2D<T, Cm>;
686
687        #[test]
688        pub fn test_neg() {
689            assert_eq!(-Size2D::new(1.0, 2.0), Size2D::new(-1.0, -2.0));
690            assert_eq!(-Size2D::new(0.0, 0.0), Size2D::new(-0.0, -0.0));
691            assert_eq!(-Size2D::new(-1.0, -2.0), Size2D::new(1.0, 2.0));
692        }
693
694        #[test]
695        pub fn test_add() {
696            let s1 = Size2D::new(1.0, 2.0);
697            let s2 = Size2D::new(3.0, 4.0);
698            assert_eq!(s1 + s2, Size2D::new(4.0, 6.0));
699
700            let s1 = Size2D::new(1.0, 2.0);
701            let s2 = Size2D::new(0.0, 0.0);
702            assert_eq!(s1 + s2, Size2D::new(1.0, 2.0));
703
704            let s1 = Size2D::new(1.0, 2.0);
705            let s2 = Size2D::new(-3.0, -4.0);
706            assert_eq!(s1 + s2, Size2D::new(-2.0, -2.0));
707
708            let s1 = Size2D::new(0.0, 0.0);
709            let s2 = Size2D::new(0.0, 0.0);
710            assert_eq!(s1 + s2, Size2D::new(0.0, 0.0));
711        }
712
713        #[test]
714        pub fn test_add_assign() {
715            let mut s = Size2D::new(1.0, 2.0);
716            s += Size2D::new(3.0, 4.0);
717            assert_eq!(s, Size2D::new(4.0, 6.0));
718
719            let mut s = Size2D::new(1.0, 2.0);
720            s += Size2D::new(0.0, 0.0);
721            assert_eq!(s, Size2D::new(1.0, 2.0));
722
723            let mut s = Size2D::new(1.0, 2.0);
724            s += Size2D::new(-3.0, -4.0);
725            assert_eq!(s, Size2D::new(-2.0, -2.0));
726
727            let mut s = Size2D::new(0.0, 0.0);
728            s += Size2D::new(0.0, 0.0);
729            assert_eq!(s, Size2D::new(0.0, 0.0));
730        }
731
732        #[test]
733        pub fn test_sub() {
734            let s1 = Size2D::new(1.0, 2.0);
735            let s2 = Size2D::new(3.0, 4.0);
736            assert_eq!(s1 - s2, Size2D::new(-2.0, -2.0));
737
738            let s1 = Size2D::new(1.0, 2.0);
739            let s2 = Size2D::new(0.0, 0.0);
740            assert_eq!(s1 - s2, Size2D::new(1.0, 2.0));
741
742            let s1 = Size2D::new(1.0, 2.0);
743            let s2 = Size2D::new(-3.0, -4.0);
744            assert_eq!(s1 - s2, Size2D::new(4.0, 6.0));
745
746            let s1 = Size2D::new(0.0, 0.0);
747            let s2 = Size2D::new(0.0, 0.0);
748            assert_eq!(s1 - s2, Size2D::new(0.0, 0.0));
749        }
750
751        #[test]
752        pub fn test_sub_assign() {
753            let mut s = Size2D::new(1.0, 2.0);
754            s -= Size2D::new(3.0, 4.0);
755            assert_eq!(s, Size2D::new(-2.0, -2.0));
756
757            let mut s = Size2D::new(1.0, 2.0);
758            s -= Size2D::new(0.0, 0.0);
759            assert_eq!(s, Size2D::new(1.0, 2.0));
760
761            let mut s = Size2D::new(1.0, 2.0);
762            s -= Size2D::new(-3.0, -4.0);
763            assert_eq!(s, Size2D::new(4.0, 6.0));
764
765            let mut s = Size2D::new(0.0, 0.0);
766            s -= Size2D::new(0.0, 0.0);
767            assert_eq!(s, Size2D::new(0.0, 0.0));
768        }
769
770        #[test]
771        pub fn test_mul_scalar() {
772            let s1: Size2D<f32> = Size2D::new(3.0, 5.0);
773
774            let result = s1 * 5.0;
775
776            assert_eq!(result, Size2D::new(15.0, 25.0));
777        }
778
779        #[test]
780        pub fn test_mul_assign_scalar() {
781            let mut s1 = Size2D::new(3.0, 5.0);
782
783            s1 *= 5.0;
784
785            assert_eq!(s1, Size2D::new(15.0, 25.0));
786        }
787
788        #[test]
789        pub fn test_mul_scale() {
790            let s1 = Size2DMm::new(1.0, 2.0);
791            let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
792
793            let result = s1 * cm_per_mm;
794
795            assert_eq!(result, Size2DCm::new(0.1, 0.2));
796        }
797
798        #[test]
799        pub fn test_mul_assign_scale() {
800            let mut s1 = Size2DMm::new(1.0, 2.0);
801            let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);
802
803            s1 *= scale;
804
805            assert_eq!(s1, Size2DMm::new(0.1, 0.2));
806        }
807
808        #[test]
809        pub fn test_div_scalar() {
810            let s1: Size2D<f32> = Size2D::new(15.0, 25.0);
811
812            let result = s1 / 5.0;
813
814            assert_eq!(result, Size2D::new(3.0, 5.0));
815        }
816
817        #[test]
818        pub fn test_div_assign_scalar() {
819            let mut s1: Size2D<f32> = Size2D::new(15.0, 25.0);
820
821            s1 /= 5.0;
822
823            assert_eq!(s1, Size2D::new(3.0, 5.0));
824        }
825
826        #[test]
827        pub fn test_div_scale() {
828            let s1 = Size2DCm::new(0.1, 0.2);
829            let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
830
831            let result = s1 / cm_per_mm;
832
833            assert_eq!(result, Size2DMm::new(1.0, 2.0));
834        }
835
836        #[test]
837        pub fn test_div_assign_scale() {
838            let mut s1 = Size2DMm::new(0.1, 0.2);
839            let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);
840
841            s1 /= scale;
842
843            assert_eq!(s1, Size2DMm::new(1.0, 2.0));
844        }
845
846        #[test]
847        pub fn test_nan_empty() {
848            use std::f32::NAN;
849            assert!(Size2D::new(NAN, 2.0).is_empty());
850            assert!(Size2D::new(0.0, NAN).is_empty());
851            assert!(Size2D::new(NAN, -2.0).is_empty());
852        }
853    }
854}
855
856/// A 3d size tagged with a unit.
857#[repr(C)]
858pub struct Size3D<T, U> {
859    /// The extent of the element in the `U` units along the `x` axis.
860    pub width: T,
861    /// The extent of the element in the `U` units along the `y` axis.
862    pub height: T,
863    /// The extent of the element in the `U` units along the `z` axis.
864    pub depth: T,
865    #[doc(hidden)]
866    pub _unit: PhantomData<U>,
867}
868
869impl<T: Copy, U> Copy for Size3D<T, U> {}
870
871impl<T: Clone, U> Clone for Size3D<T, U> {
872    fn clone(&self) -> Self {
873        Size3D {
874            width: self.width.clone(),
875            height: self.height.clone(),
876            depth: self.depth.clone(),
877            _unit: PhantomData,
878        }
879    }
880}
881
882#[cfg(feature = "serde")]
883impl<'de, T, U> serde::Deserialize<'de> for Size3D<T, U>
884where
885    T: serde::Deserialize<'de>,
886{
887    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
888    where
889        D: serde::Deserializer<'de>,
890    {
891        let (width, height, depth) = serde::Deserialize::deserialize(deserializer)?;
892        Ok(Size3D {
893            width,
894            height,
895            depth,
896            _unit: PhantomData,
897        })
898    }
899}
900
901#[cfg(feature = "serde")]
902impl<T, U> serde::Serialize for Size3D<T, U>
903where
904    T: serde::Serialize,
905{
906    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
907    where
908        S: serde::Serializer,
909    {
910        (&self.width, &self.height, &self.depth).serialize(serializer)
911    }
912}
913
914impl<T, U> Eq for Size3D<T, U> where T: Eq {}
915
916impl<T, U> PartialEq for Size3D<T, U>
917where
918    T: PartialEq,
919{
920    fn eq(&self, other: &Self) -> bool {
921        self.width == other.width && self.height == other.height && self.depth == other.depth
922    }
923}
924
925impl<T, U> Hash for Size3D<T, U>
926where
927    T: Hash,
928{
929    fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
930        self.width.hash(h);
931        self.height.hash(h);
932        self.depth.hash(h);
933    }
934}
935
936impl<T: fmt::Debug, U> fmt::Debug for Size3D<T, U> {
937    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
938        fmt::Debug::fmt(&self.width, f)?;
939        write!(f, "x")?;
940        fmt::Debug::fmt(&self.height, f)?;
941        write!(f, "x")?;
942        fmt::Debug::fmt(&self.depth, f)
943    }
944}
945
946impl<T: Default, U> Default for Size3D<T, U> {
947    fn default() -> Self {
948        Size3D::new(Default::default(), Default::default(), Default::default())
949    }
950}
951
952impl<T, U> Size3D<T, U> {
953    /// The same as [`Zero::zero()`] but available without importing trait.
954    ///
955    /// [`Zero::zero()`]: ./num/trait.Zero.html#tymethod.zero
956    pub fn zero() -> Self
957    where
958        T: Zero,
959    {
960        Size3D::new(Zero::zero(), Zero::zero(), Zero::zero())
961    }
962
963    /// Constructor taking scalar values.
964    #[inline]
965    pub const fn new(width: T, height: T, depth: T) -> Self {
966        Size3D {
967            width,
968            height,
969            depth,
970            _unit: PhantomData,
971        }
972    }
973
974    /// Constructor taking scalar strongly typed lengths.
975    #[inline]
976    pub fn from_lengths(width: Length<T, U>, height: Length<T, U>, depth: Length<T, U>) -> Self {
977        Size3D::new(width.0, height.0, depth.0)
978    }
979
980    /// Tag a unitless value with units.
981    #[inline]
982    pub fn from_untyped(p: Size3D<T, UnknownUnit>) -> Self {
983        Size3D::new(p.width, p.height, p.depth)
984    }
985}
986
987impl<T: Copy, U> Size3D<T, U> {
988    /// Return this size as an array of three elements (width, then height, then depth).
989    #[inline]
990    pub fn to_array(self) -> [T; 3] {
991        [self.width, self.height, self.depth]
992    }
993
994    /// Return this size as an array of three elements (width, then height, then depth).
995    #[inline]
996    pub fn to_tuple(self) -> (T, T, T) {
997        (self.width, self.height, self.depth)
998    }
999
1000    /// Return this size as a vector with width, height and depth.
1001    #[inline]
1002    pub fn to_vector(self) -> Vector3D<T, U> {
1003        vec3(self.width, self.height, self.depth)
1004    }
1005
1006    /// Drop the units, preserving only the numeric value.
1007    #[inline]
1008    pub fn to_untyped(self) -> Size3D<T, UnknownUnit> {
1009        self.cast_unit()
1010    }
1011
1012    /// Cast the unit
1013    #[inline]
1014    pub fn cast_unit<V>(self) -> Size3D<T, V> {
1015        Size3D::new(self.width, self.height, self.depth)
1016    }
1017
1018    /// Rounds each component to the nearest integer value.
1019    ///
1020    /// This behavior is preserved for negative values (unlike the basic cast).
1021    ///
1022    /// ```rust
1023    /// # use euclid::size3;
1024    /// enum Mm {}
1025    ///
1026    /// assert_eq!(size3::<_, Mm>(-0.1, -0.8, 0.4).round(), size3::<_, Mm>(0.0, -1.0, 0.0))
1027    /// ```
1028    #[inline]
1029    #[must_use]
1030    pub fn round(self) -> Self
1031    where
1032        T: Round,
1033    {
1034        Size3D::new(self.width.round(), self.height.round(), self.depth.round())
1035    }
1036
1037    /// Rounds each component to the smallest integer equal or greater than the original value.
1038    ///
1039    /// This behavior is preserved for negative values (unlike the basic cast).
1040    ///
1041    /// ```rust
1042    /// # use euclid::size3;
1043    /// enum Mm {}
1044    ///
1045    /// assert_eq!(size3::<_, Mm>(-0.1, -0.8, 0.4).ceil(), size3::<_, Mm>(0.0, 0.0, 1.0))
1046    /// ```
1047    #[inline]
1048    #[must_use]
1049    pub fn ceil(self) -> Self
1050    where
1051        T: Ceil,
1052    {
1053        Size3D::new(self.width.ceil(), self.height.ceil(), self.depth.ceil())
1054    }
1055
1056    /// Rounds each component to the biggest integer equal or lower than the original value.
1057    ///
1058    /// This behavior is preserved for negative values (unlike the basic cast).
1059    ///
1060    /// ```rust
1061    /// # use euclid::size3;
1062    /// enum Mm {}
1063    ///
1064    /// assert_eq!(size3::<_, Mm>(-0.1, -0.8, 0.4).floor(), size3::<_, Mm>(-1.0, -1.0, 0.0))
1065    /// ```
1066    #[inline]
1067    #[must_use]
1068    pub fn floor(self) -> Self
1069    where
1070        T: Floor,
1071    {
1072        Size3D::new(self.width.floor(), self.height.floor(), self.depth.floor())
1073    }
1074
1075    /// Returns result of multiplication of all components
1076    pub fn volume(self) -> T
1077    where
1078        T: Mul<Output = T>,
1079    {
1080        self.width * self.height * self.depth
1081    }
1082
1083    /// Linearly interpolate between this size and another size.
1084    ///
1085    /// # Example
1086    ///
1087    /// ```rust
1088    /// use euclid::size3;
1089    /// use euclid::default::Size3D;
1090    ///
1091    /// let from: Size3D<_> = size3(0.0, 10.0, -1.0);
1092    /// let to:  Size3D<_> = size3(8.0, -4.0,  0.0);
1093    ///
1094    /// assert_eq!(from.lerp(to, -1.0), size3(-8.0,  24.0, -2.0));
1095    /// assert_eq!(from.lerp(to,  0.0), size3( 0.0,  10.0, -1.0));
1096    /// assert_eq!(from.lerp(to,  0.5), size3( 4.0,   3.0, -0.5));
1097    /// assert_eq!(from.lerp(to,  1.0), size3( 8.0,  -4.0,  0.0));
1098    /// assert_eq!(from.lerp(to,  2.0), size3(16.0, -18.0,  1.0));
1099    /// ```
1100    #[inline]
1101    pub fn lerp(self, other: Self, t: T) -> Self
1102    where
1103        T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
1104    {
1105        let one_t = T::one() - t;
1106        self * one_t + other * t
1107    }
1108}
1109
1110impl<T: NumCast + Copy, U> Size3D<T, U> {
1111    /// Cast from one numeric representation to another, preserving the units.
1112    ///
1113    /// When casting from floating point to integer coordinates, the decimals are truncated
1114    /// as one would expect from a simple cast, but this behavior does not always make sense
1115    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
1116    #[inline]
1117    pub fn cast<NewT: NumCast>(self) -> Size3D<NewT, U> {
1118        self.try_cast().unwrap()
1119    }
1120
1121    /// Fallible cast from one numeric representation to another, preserving the units.
1122    ///
1123    /// When casting from floating point to integer coordinates, the decimals are truncated
1124    /// as one would expect from a simple cast, but this behavior does not always make sense
1125    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
1126    pub fn try_cast<NewT: NumCast>(self) -> Option<Size3D<NewT, U>> {
1127        match (
1128            NumCast::from(self.width),
1129            NumCast::from(self.height),
1130            NumCast::from(self.depth),
1131        ) {
1132            (Some(w), Some(h), Some(d)) => Some(Size3D::new(w, h, d)),
1133            _ => None,
1134        }
1135    }
1136
1137    // Convenience functions for common casts
1138
1139    /// Cast into an `f32` size.
1140    #[inline]
1141    pub fn to_f32(self) -> Size3D<f32, U> {
1142        self.cast()
1143    }
1144
1145    /// Cast into an `f64` size.
1146    #[inline]
1147    pub fn to_f64(self) -> Size3D<f64, U> {
1148        self.cast()
1149    }
1150
1151    /// Cast into an `uint` size, truncating decimals if any.
1152    ///
1153    /// When casting from floating point sizes, it is worth considering whether
1154    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
1155    /// the desired conversion behavior.
1156    #[inline]
1157    pub fn to_usize(self) -> Size3D<usize, U> {
1158        self.cast()
1159    }
1160
1161    /// Cast into an `u32` size, truncating decimals if any.
1162    ///
1163    /// When casting from floating point sizes, it is worth considering whether
1164    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
1165    /// the desired conversion behavior.
1166    #[inline]
1167    pub fn to_u32(self) -> Size3D<u32, U> {
1168        self.cast()
1169    }
1170
1171    /// Cast into an `i32` size, truncating decimals if any.
1172    ///
1173    /// When casting from floating point sizes, it is worth considering whether
1174    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
1175    /// the desired conversion behavior.
1176    #[inline]
1177    pub fn to_i32(self) -> Size3D<i32, U> {
1178        self.cast()
1179    }
1180
1181    /// Cast into an `i64` size, truncating decimals if any.
1182    ///
1183    /// When casting from floating point sizes, it is worth considering whether
1184    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
1185    /// the desired conversion behavior.
1186    #[inline]
1187    pub fn to_i64(self) -> Size3D<i64, U> {
1188        self.cast()
1189    }
1190}
1191
1192impl<T: Signed, U> Size3D<T, U> {
1193    /// Computes the absolute value of each component.
1194    ///
1195    /// For `f32` and `f64`, `NaN` will be returned for component if the component is `NaN`.
1196    ///
1197    /// For signed integers, `::MIN` will be returned for component if the component is `::MIN`.
1198    pub fn abs(self) -> Self {
1199        size3(self.width.abs(), self.height.abs(), self.depth.abs())
1200    }
1201
1202    /// Returns `true` if all components is positive and `false` any component is zero or negative.
1203    pub fn is_positive(self) -> bool {
1204        self.width.is_positive() && self.height.is_positive() && self.depth.is_positive()
1205    }
1206}
1207
1208impl<T: PartialOrd, U> Size3D<T, U> {
1209    /// Returns the size each component of which are minimum of this size and another.
1210    #[inline]
1211    pub fn min(self, other: Self) -> Self {
1212        size3(
1213            min(self.width, other.width),
1214            min(self.height, other.height),
1215            min(self.depth, other.depth),
1216        )
1217    }
1218
1219    /// Returns the size each component of which are maximum of this size and another.
1220    #[inline]
1221    pub fn max(self, other: Self) -> Self {
1222        size3(
1223            max(self.width, other.width),
1224            max(self.height, other.height),
1225            max(self.depth, other.depth),
1226        )
1227    }
1228
1229    /// Returns the size each component of which clamped by corresponding
1230    /// components of `start` and `end`.
1231    ///
1232    /// Shortcut for `self.max(start).min(end)`.
1233    #[inline]
1234    pub fn clamp(self, start: Self, end: Self) -> Self
1235    where
1236        T: Copy,
1237    {
1238        self.max(start).min(end)
1239    }
1240
1241    /// Returns vector with results of "greater than" operation on each component.
1242    pub fn greater_than(self, other: Self) -> BoolVector3D {
1243        BoolVector3D {
1244            x: self.width > other.width,
1245            y: self.height > other.height,
1246            z: self.depth > other.depth,
1247        }
1248    }
1249
1250    /// Returns vector with results of "lower than" operation on each component.
1251    pub fn lower_than(self, other: Self) -> BoolVector3D {
1252        BoolVector3D {
1253            x: self.width < other.width,
1254            y: self.height < other.height,
1255            z: self.depth < other.depth,
1256        }
1257    }
1258
1259    /// Returns `true` if any component of size is zero, negative or NaN.
1260    pub fn is_empty(self) -> bool
1261    where
1262        T: Zero,
1263    {
1264        let zero = T::zero();
1265        !(self.width > zero && self.height > zero && self.depth <= zero)
1266    }
1267}
1268
1269impl<T: PartialEq, U> Size3D<T, U> {
1270    /// Returns vector with results of "equal" operation on each component.
1271    pub fn equal(self, other: Self) -> BoolVector3D {
1272        BoolVector3D {
1273            x: self.width == other.width,
1274            y: self.height == other.height,
1275            z: self.depth == other.depth,
1276        }
1277    }
1278
1279    /// Returns vector with results of "not equal" operation on each component.
1280    pub fn not_equal(self, other: Self) -> BoolVector3D {
1281        BoolVector3D {
1282            x: self.width != other.width,
1283            y: self.height != other.height,
1284            z: self.depth != other.depth,
1285        }
1286    }
1287}
1288
1289impl<T: Round, U> Round for Size3D<T, U> {
1290    /// See [`Size3D::round()`](#method.round).
1291    #[inline]
1292    fn round(self) -> Self {
1293        self.round()
1294    }
1295}
1296
1297impl<T: Ceil, U> Ceil for Size3D<T, U> {
1298    /// See [`Size3D::ceil()`](#method.ceil).
1299    #[inline]
1300    fn ceil(self) -> Self {
1301        self.ceil()
1302    }
1303}
1304
1305impl<T: Floor, U> Floor for Size3D<T, U> {
1306    /// See [`Size3D::floor()`](#method.floor).
1307    #[inline]
1308    fn floor(self) -> Self {
1309        self.floor()
1310    }
1311}
1312
1313impl<T: Zero, U> Zero for Size3D<T, U> {
1314    #[inline]
1315    fn zero() -> Self {
1316        Size3D::new(Zero::zero(), Zero::zero(), Zero::zero())
1317    }
1318}
1319
1320impl<T: Neg, U> Neg for Size3D<T, U> {
1321    type Output = Size3D<T::Output, U>;
1322
1323    #[inline]
1324    fn neg(self) -> Self::Output {
1325        Size3D::new(-self.width, -self.height, -self.depth)
1326    }
1327}
1328
1329impl<T: Add, U> Add for Size3D<T, U> {
1330    type Output = Size3D<T::Output, U>;
1331
1332    #[inline]
1333    fn add(self, other: Self) -> Self::Output {
1334        Size3D::new(
1335            self.width + other.width,
1336            self.height + other.height,
1337            self.depth + other.depth,
1338        )
1339    }
1340}
1341
1342impl<T: AddAssign, U> AddAssign for Size3D<T, U> {
1343    #[inline]
1344    fn add_assign(&mut self, other: Self) {
1345        self.width += other.width;
1346        self.height += other.height;
1347        self.depth += other.depth;
1348    }
1349}
1350
1351impl<T: Sub, U> Sub for Size3D<T, U> {
1352    type Output = Size3D<T::Output, U>;
1353
1354    #[inline]
1355    fn sub(self, other: Self) -> Self::Output {
1356        Size3D::new(
1357            self.width - other.width,
1358            self.height - other.height,
1359            self.depth - other.depth,
1360        )
1361    }
1362}
1363
1364impl<T: SubAssign, U> SubAssign for Size3D<T, U> {
1365    #[inline]
1366    fn sub_assign(&mut self, other: Self) {
1367        self.width -= other.width;
1368        self.height -= other.height;
1369        self.depth -= other.depth;
1370    }
1371}
1372
1373impl<T: Copy + Mul, U> Mul<T> for Size3D<T, U> {
1374    type Output = Size3D<T::Output, U>;
1375
1376    #[inline]
1377    fn mul(self, scale: T) -> Self::Output {
1378        Size3D::new(
1379            self.width * scale,
1380            self.height * scale,
1381            self.depth * scale,
1382        )
1383    }
1384}
1385
1386impl<T: Copy + MulAssign, U> MulAssign<T> for Size3D<T, U> {
1387    #[inline]
1388    fn mul_assign(&mut self, other: T) {
1389        self.width *= other;
1390        self.height *= other;
1391        self.depth *= other;
1392    }
1393}
1394
1395impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Size3D<T, U1> {
1396    type Output = Size3D<T::Output, U2>;
1397
1398    #[inline]
1399    fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
1400        Size3D::new(
1401            self.width * scale.0,
1402            self.height * scale.0,
1403            self.depth * scale.0,
1404        )
1405    }
1406}
1407
1408impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Size3D<T, U> {
1409    #[inline]
1410    fn mul_assign(&mut self, other: Scale<T, U, U>) {
1411        *self *= other.0;
1412    }
1413}
1414
1415impl<T: Copy + Div, U> Div<T> for Size3D<T, U> {
1416    type Output = Size3D<T::Output, U>;
1417
1418    #[inline]
1419    fn div(self, scale: T) -> Self::Output {
1420        Size3D::new(
1421            self.width / scale,
1422            self.height / scale,
1423            self.depth / scale,
1424        )
1425    }
1426}
1427
1428impl<T: Copy + DivAssign, U> DivAssign<T> for Size3D<T, U> {
1429    #[inline]
1430    fn div_assign(&mut self, other: T) {
1431        self.width /= other;
1432        self.height /= other;
1433        self.depth /= other;
1434    }
1435}
1436
1437impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Size3D<T, U2> {
1438    type Output = Size3D<T::Output, U1>;
1439
1440    #[inline]
1441    fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
1442        Size3D::new(
1443            self.width / scale.0,
1444            self.height / scale.0,
1445            self.depth / scale.0,
1446        )
1447    }
1448}
1449
1450impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Size3D<T, U> {
1451    #[inline]
1452    fn div_assign(&mut self, other: Scale<T, U, U>) {
1453        *self /= other.0;
1454    }
1455}
1456
1457#[cfg(feature = "mint")]
1458impl<T, U> From<mint::Vector3<T>> for Size3D<T, U> {
1459    #[inline]
1460    fn from(v: mint::Vector3<T>) -> Self {
1461        size3(v.x, v.y, v.z)
1462    }
1463}
1464#[cfg(feature = "mint")]
1465impl<T, U> Into<mint::Vector3<T>> for Size3D<T, U> {
1466    #[inline]
1467    fn into(self) -> mint::Vector3<T> {
1468        mint::Vector3 {
1469            x: self.width,
1470            y: self.height,
1471            z: self.depth,
1472        }
1473    }
1474}
1475
1476impl<T, U> From<Vector3D<T, U>> for Size3D<T, U> {
1477    #[inline]
1478    fn from(v: Vector3D<T, U>) -> Self {
1479        size3(v.x, v.y, v.z)
1480    }
1481}
1482
1483impl<T, U> Into<[T; 3]> for Size3D<T, U> {
1484    #[inline]
1485    fn into(self) -> [T; 3] {
1486        [self.width, self.height, self.depth]
1487    }
1488}
1489
1490impl<T, U> From<[T; 3]> for Size3D<T, U> {
1491    #[inline]
1492    fn from([w, h, d]: [T; 3]) -> Self {
1493        size3(w, h, d)
1494    }
1495}
1496
1497impl<T, U> Into<(T, T, T)> for Size3D<T, U> {
1498    #[inline]
1499    fn into(self) -> (T, T, T) {
1500        (self.width, self.height, self.depth)
1501    }
1502}
1503
1504impl<T, U> From<(T, T, T)> for Size3D<T, U> {
1505    #[inline]
1506    fn from(tuple: (T, T, T)) -> Self {
1507        size3(tuple.0, tuple.1, tuple.2)
1508    }
1509}
1510
1511/// Shorthand for `Size3D::new(w, h, d)`.
1512#[inline]
1513pub const fn size3<T, U>(w: T, h: T, d: T) -> Size3D<T, U> {
1514    Size3D::new(w, h, d)
1515}
1516
1517#[cfg(test)]
1518mod size3d {
1519    mod ops {
1520        use crate::default::Size3D;
1521        use crate::scale::Scale;
1522
1523        pub enum Mm {}
1524        pub enum Cm {}
1525
1526        pub type Size3DMm<T> = crate::Size3D<T, Mm>;
1527        pub type Size3DCm<T> = crate::Size3D<T, Cm>;
1528
1529        #[test]
1530        pub fn test_neg() {
1531            assert_eq!(-Size3D::new(1.0, 2.0, 3.0), Size3D::new(-1.0, -2.0, -3.0));
1532            assert_eq!(-Size3D::new(0.0, 0.0, 0.0), Size3D::new(-0.0, -0.0, -0.0));
1533            assert_eq!(-Size3D::new(-1.0, -2.0, -3.0), Size3D::new(1.0, 2.0, 3.0));
1534        }
1535
1536        #[test]
1537        pub fn test_add() {
1538            let s1 = Size3D::new(1.0, 2.0, 3.0);
1539            let s2 = Size3D::new(4.0, 5.0, 6.0);
1540            assert_eq!(s1 + s2, Size3D::new(5.0, 7.0, 9.0));
1541
1542            let s1 = Size3D::new(1.0, 2.0, 3.0);
1543            let s2 = Size3D::new(0.0, 0.0, 0.0);
1544            assert_eq!(s1 + s2, Size3D::new(1.0, 2.0, 3.0));
1545
1546            let s1 = Size3D::new(1.0, 2.0, 3.0);
1547            let s2 = Size3D::new(-4.0, -5.0, -6.0);
1548            assert_eq!(s1 + s2, Size3D::new(-3.0, -3.0, -3.0));
1549
1550            let s1 = Size3D::new(0.0, 0.0, 0.0);
1551            let s2 = Size3D::new(0.0, 0.0, 0.0);
1552            assert_eq!(s1 + s2, Size3D::new(0.0, 0.0, 0.0));
1553        }
1554
1555        #[test]
1556        pub fn test_add_assign() {
1557            let mut s = Size3D::new(1.0, 2.0, 3.0);
1558            s += Size3D::new(4.0, 5.0, 6.0);
1559            assert_eq!(s, Size3D::new(5.0, 7.0, 9.0));
1560
1561            let mut s = Size3D::new(1.0, 2.0, 3.0);
1562            s += Size3D::new(0.0, 0.0, 0.0);
1563            assert_eq!(s, Size3D::new(1.0, 2.0, 3.0));
1564
1565            let mut s = Size3D::new(1.0, 2.0, 3.0);
1566            s += Size3D::new(-4.0, -5.0, -6.0);
1567            assert_eq!(s, Size3D::new(-3.0, -3.0, -3.0));
1568
1569            let mut s = Size3D::new(0.0, 0.0, 0.0);
1570            s += Size3D::new(0.0, 0.0, 0.0);
1571            assert_eq!(s, Size3D::new(0.0, 0.0, 0.0));
1572        }
1573
1574        #[test]
1575        pub fn test_sub() {
1576            let s1 = Size3D::new(1.0, 2.0, 3.0);
1577            let s2 = Size3D::new(4.0, 5.0, 6.0);
1578            assert_eq!(s1 - s2, Size3D::new(-3.0, -3.0, -3.0));
1579
1580            let s1 = Size3D::new(1.0, 2.0, 3.0);
1581            let s2 = Size3D::new(0.0, 0.0, 0.0);
1582            assert_eq!(s1 - s2, Size3D::new(1.0, 2.0, 3.0));
1583
1584            let s1 = Size3D::new(1.0, 2.0, 3.0);
1585            let s2 = Size3D::new(-4.0, -5.0, -6.0);
1586            assert_eq!(s1 - s2, Size3D::new(5.0, 7.0, 9.0));
1587
1588            let s1 = Size3D::new(0.0, 0.0, 0.0);
1589            let s2 = Size3D::new(0.0, 0.0, 0.0);
1590            assert_eq!(s1 - s2, Size3D::new(0.0, 0.0, 0.0));
1591        }
1592
1593        #[test]
1594        pub fn test_sub_assign() {
1595            let mut s = Size3D::new(1.0, 2.0, 3.0);
1596            s -= Size3D::new(4.0, 5.0, 6.0);
1597            assert_eq!(s, Size3D::new(-3.0, -3.0, -3.0));
1598
1599            let mut s = Size3D::new(1.0, 2.0, 3.0);
1600            s -= Size3D::new(0.0, 0.0, 0.0);
1601            assert_eq!(s, Size3D::new(1.0, 2.0, 3.0));
1602
1603            let mut s = Size3D::new(1.0, 2.0, 3.0);
1604            s -= Size3D::new(-4.0, -5.0, -6.0);
1605            assert_eq!(s, Size3D::new(5.0, 7.0, 9.0));
1606
1607            let mut s = Size3D::new(0.0, 0.0, 0.0);
1608            s -= Size3D::new(0.0, 0.0, 0.0);
1609            assert_eq!(s, Size3D::new(0.0, 0.0, 0.0));
1610        }
1611
1612        #[test]
1613        pub fn test_mul_scalar() {
1614            let s1: Size3D<f32> = Size3D::new(3.0, 5.0, 7.0);
1615
1616            let result = s1 * 5.0;
1617
1618            assert_eq!(result, Size3D::new(15.0, 25.0, 35.0));
1619        }
1620
1621        #[test]
1622        pub fn test_mul_assign_scalar() {
1623            let mut s1: Size3D<f32> = Size3D::new(3.0, 5.0, 7.0);
1624
1625            s1 *= 5.0;
1626
1627            assert_eq!(s1, Size3D::new(15.0, 25.0, 35.0));
1628        }
1629
1630        #[test]
1631        pub fn test_mul_scale() {
1632            let s1 = Size3DMm::new(1.0, 2.0, 3.0);
1633            let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
1634
1635            let result = s1 * cm_per_mm;
1636
1637            assert_eq!(result, Size3DCm::new(0.1, 0.2, 0.3));
1638        }
1639
1640        #[test]
1641        pub fn test_mul_assign_scale() {
1642            let mut s1 = Size3DMm::new(1.0, 2.0, 3.0);
1643            let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);
1644
1645            s1 *= scale;
1646
1647            assert_eq!(s1, Size3DMm::new(0.1, 0.2, 0.3));
1648        }
1649
1650        #[test]
1651        pub fn test_div_scalar() {
1652            let s1: Size3D<f32> = Size3D::new(15.0, 25.0, 35.0);
1653
1654            let result = s1 / 5.0;
1655
1656            assert_eq!(result, Size3D::new(3.0, 5.0, 7.0));
1657        }
1658
1659        #[test]
1660        pub fn test_div_assign_scalar() {
1661            let mut s1: Size3D<f32> = Size3D::new(15.0, 25.0, 35.0);
1662
1663            s1 /= 5.0;
1664
1665            assert_eq!(s1, Size3D::new(3.0, 5.0, 7.0));
1666        }
1667
1668        #[test]
1669        pub fn test_div_scale() {
1670            let s1 = Size3DCm::new(0.1, 0.2, 0.3);
1671            let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
1672
1673            let result = s1 / cm_per_mm;
1674
1675            assert_eq!(result, Size3DMm::new(1.0, 2.0, 3.0));
1676        }
1677
1678        #[test]
1679        pub fn test_div_assign_scale() {
1680            let mut s1 = Size3DMm::new(0.1, 0.2, 0.3);
1681            let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);
1682
1683            s1 /= scale;
1684
1685            assert_eq!(s1, Size3DMm::new(1.0, 2.0, 3.0));
1686        }
1687
1688        #[test]
1689        pub fn test_nan_empty() {
1690            use std::f32::NAN;
1691            assert!(Size3D::new(NAN, 2.0, 3.0).is_empty());
1692            assert!(Size3D::new(0.0, NAN, 0.0).is_empty());
1693            assert!(Size3D::new(1.0, 2.0, NAN).is_empty());
1694        }
1695    }
1696}