Skip to main content

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