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