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