primitives/foundation/
size2d.rs

1use std::{
2    cmp::{Eq, PartialEq},
3    fmt,
4    hash::Hash,
5    iter::Sum,
6    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
7};
8
9use crate::prelude::{One, Zero};
10
11/// A 2d size tagged with a unit.
12#[repr(C)]
13pub struct Size2D<T> {
14    /// The extent of the element in the `U` units along the `x` axis (usually horizontal).
15    pub width: T,
16    /// The extent of the element in the `U` units along the `y` axis (usually vertical).
17    pub height: T,
18}
19
20impl<T: Copy> Copy for Size2D<T> {}
21
22impl<T: Clone> Clone for Size2D<T> {
23    fn clone(&self) -> Self {
24        Size2D {
25            width: self.width.clone(),
26            height: self.height.clone(),
27        }
28    }
29}
30
31#[cfg(feature = "serde")]
32impl<'de, T> serde::Deserialize<'de> for Size2D<T>
33where
34    T: serde::Deserialize<'de>,
35{
36    /// Deserializes 2d size from tuple of width and height.
37    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
38    where
39        D: serde::Deserializer<'de>,
40    {
41        let (width, height) = serde::Deserialize::deserialize(deserializer)?;
42        Ok(Size2D {
43            width,
44            height,
45            _unit: PhantomData,
46        })
47    }
48}
49
50#[cfg(feature = "serde")]
51impl<T> serde::Serialize for Size2D<T>
52where
53    T: serde::Serialize,
54{
55    /// Serializes 2d size to tuple of width and height.
56    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
57    where
58        S: serde::Serializer,
59    {
60        (&self.width, &self.height).serialize(serializer)
61    }
62}
63
64#[cfg(feature = "arbitrary")]
65impl<'a, T> arbitrary::Arbitrary<'a> for Size2D<T>
66where
67    T: arbitrary::Arbitrary<'a>,
68{
69    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
70        let (width, height) = arbitrary::Arbitrary::arbitrary(u)?;
71        Ok(Size2D {
72            width,
73            height,
74            _unit: PhantomData,
75        })
76    }
77}
78
79impl<T> Eq for Size2D<T> where T: Eq {}
80
81impl<T> PartialEq for Size2D<T>
82where
83    T: PartialEq,
84{
85    fn eq(&self, other: &Self) -> bool {
86        self.width == other.width && self.height == other.height
87    }
88}
89
90impl<T> Hash for Size2D<T>
91where
92    T: Hash,
93{
94    fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
95        self.width.hash(h);
96        self.height.hash(h);
97    }
98}
99
100impl<T: fmt::Debug> fmt::Debug for Size2D<T> {
101    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102        fmt::Debug::fmt(&self.width, f)?;
103        write!(f, "x")?;
104        fmt::Debug::fmt(&self.height, f)
105    }
106}
107
108impl<T: Default> Default for Size2D<T> {
109    fn default() -> Self {
110        Size2D::new(Default::default(), Default::default())
111    }
112}
113
114impl<T> Size2D<T> {
115    /// The same as [`Zero::zero()`] but available without importing trait.
116    ///
117    /// [`Zero::zero()`]: ./num/trait.Zero.html#tymethod.zero
118    #[inline]
119    pub fn zero() -> Self
120    where
121        T: Zero,
122    {
123        Size2D::new(Zero::zero(), Zero::zero())
124    }
125
126    /// Constructor taking scalar values.
127    #[inline]
128    pub const fn new(width: T, height: T) -> Self {
129        Size2D { width, height }
130    }
131
132    // TODO:
133    // /// Constructor taking scalar strongly typed lengths.
134    // #[inline]
135    // pub fn from_lengths(width: Length<T>, height: Length<T>) -> Self {
136    //     Size2D::new(width.0, height.0)
137    // }
138
139    /// Constructor setting all components to the same value.
140    #[inline]
141    pub fn splat(v: T) -> Self
142    where
143        T: Clone,
144    {
145        Size2D {
146            width: v.clone(),
147            height: v,
148        }
149    }
150
151    /// Tag a unitless value with units.
152    #[inline]
153    pub fn from_untyped(p: Size2D<T>) -> Self {
154        Size2D::new(p.width, p.height)
155    }
156}
157
158impl<T: Copy> Size2D<T> {
159    /// Return this size as an array of two elements (width, then height).
160    #[inline]
161    pub fn to_array(self) -> [T; 2] {
162        [self.width, self.height]
163    }
164
165    /// Return this size as a tuple of two elements (width, then height).
166    #[inline]
167    pub fn to_tuple(self) -> (T, T) {
168        (self.width, self.height)
169    }
170
171    // TODO:
172    // /// Return this size as a vector with width and height.
173    // #[inline]
174    // pub fn to_vector(self) -> Vector2D<T> {
175    //     vec2(self.width, self.height)
176    // }
177
178    // /// Drop the units, preserving only the numeric value.
179    // #[inline]
180    // pub fn to_untyped(self) -> Size2D<T> {
181    //     self.cast_unit()
182    // }
183
184    // /// Cast the unit
185    // #[inline]
186    // pub fn cast_unit<V>(self) -> Size2D<T, V> {
187    //     Size2D::new(self.width, self.height)
188    // }
189
190    // TODO:
191    // /// Rounds each component to the nearest integer value.
192    // ///
193    // /// This behavior is preserved for negative values (unlike the basic cast).
194    // ///
195    // /// ```rust
196    // /// # use euclid::size2;
197    // /// enum Mm {}
198    // ///
199    // /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).round(), size2::<_, Mm>(0.0, -1.0))
200    // /// ```
201    // #[inline]
202    // #[must_use]
203    // pub fn round(self) -> Self
204    // where
205    //     T: Round,
206    // {
207    //     Size2D::new(self.width.round(), self.height.round())
208    // }
209
210    // TODO:
211    // /// Rounds each component to the smallest integer equal or greater than the original value.
212    // ///
213    // /// This behavior is preserved for negative values (unlike the basic cast).
214    // ///
215    // /// ```rust
216    // /// # use euclid::size2;
217    // /// enum Mm {}
218    // ///
219    // /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).ceil(), size2::<_, Mm>(0.0, 0.0))
220    // /// ```
221    // #[inline]
222    // #[must_use]
223    // pub fn ceil(self) -> Self
224    // where
225    //     T: Ceil,
226    // {
227    //     Size2D::new(self.width.ceil(), self.height.ceil())
228    // }
229
230    // TODO:
231    // /// Rounds each component to the biggest integer equal or lower than the original value.
232    // ///
233    // /// This behavior is preserved for negative values (unlike the basic cast).
234    // ///
235    // /// ```rust
236    // /// # use euclid::size2;
237    // /// enum Mm {}
238    // ///
239    // /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).floor(), size2::<_, Mm>(-1.0, -1.0))
240    // /// ```
241    // #[inline]
242    // #[must_use]
243    // pub fn floor(self) -> Self
244    // where
245    //     T: Floor,
246    // {
247    //     Size2D::new(self.width.floor(), self.height.floor())
248    // }
249
250    /// Returns result of multiplication of both components
251    pub fn area(self) -> T::Output
252    where
253        T: Mul,
254    {
255        self.width * self.height
256    }
257
258    /// Linearly interpolate each component between this size and another size.
259    #[inline]
260    pub fn lerp(self, other: Self, t: T) -> Self
261    where
262        T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
263    {
264        let one_t = T::one() - t;
265        self * one_t + other * t
266    }
267}
268
269// impl<T: NumCast + Copy> Size2D<T> {
270//     /// Cast from one numeric representation to another, preserving the units.
271//     ///
272//     /// When casting from floating point to integer coordinates, the decimals are truncated
273//     /// as one would expect from a simple cast, but this behavior does not always make sense
274//     /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
275//     #[inline]
276//     pub fn cast<NewT: NumCast>(self) -> Size2D<NewT> {
277//         self.try_cast().unwrap()
278//     }
279
280//     /// Fallible cast from one numeric representation to another, preserving the units.
281//     ///
282//     /// When casting from floating point to integer coordinates, the decimals are truncated
283//     /// as one would expect from a simple cast, but this behavior does not always make sense
284//     /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
285//     pub fn try_cast<NewT: NumCast>(self) -> Option<Size2D<NewT>> {
286//         match (NumCast::from(self.width), NumCast::from(self.height)) {
287//             (Some(w), Some(h)) => Some(Size2D::new(w, h)),
288//             _ => None,
289//         }
290//     }
291
292//     // Convenience functions for common casts
293
294//     /// Cast into an `f32` size.
295//     #[inline]
296//     pub fn to_f32(self) -> Size2D<f32> {
297//         self.cast()
298//     }
299
300//     /// Cast into an `f64` size.
301//     #[inline]
302//     pub fn to_f64(self) -> Size2D<f64> {
303//         self.cast()
304//     }
305
306//     /// Cast into an `uint` size, truncating decimals if any.
307//     ///
308//     /// When casting from floating point sizes, it is worth considering whether
309//     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
310//     /// the desired conversion behavior.
311//     #[inline]
312//     pub fn to_usize(self) -> Size2D<usize> {
313//         self.cast()
314//     }
315
316//     /// Cast into an `u32` size, truncating decimals if any.
317//     ///
318//     /// When casting from floating point sizes, it is worth considering whether
319//     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
320//     /// the desired conversion behavior.
321//     #[inline]
322//     pub fn to_u32(self) -> Size2D<u32> {
323//         self.cast()
324//     }
325
326//     /// Cast into an `u64` size, truncating decimals if any.
327//     ///
328//     /// When casting from floating point sizes, it is worth considering whether
329//     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
330//     /// the desired conversion behavior.
331//     #[inline]
332//     pub fn to_u64(self) -> Size2D<u64> {
333//         self.cast()
334//     }
335
336//     /// Cast into an `i32` size, truncating decimals if any.
337//     ///
338//     /// When casting from floating point sizes, it is worth considering whether
339//     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
340//     /// the desired conversion behavior.
341//     #[inline]
342//     pub fn to_i32(self) -> Size2D<i32> {
343//         self.cast()
344//     }
345
346//     /// Cast into an `i64` size, truncating decimals if any.
347//     ///
348//     /// When casting from floating point sizes, it is worth considering whether
349//     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
350//     /// the desired conversion behavior.
351//     #[inline]
352//     pub fn to_i64(self) -> Size2D<i64> {
353//         self.cast()
354//     }
355// }
356
357// impl<T: Float> Size2D<T> {
358//     /// Returns true if all members are finite.
359//     #[inline]
360//     pub fn is_finite(self) -> bool {
361//         self.width.is_finite() && self.height.is_finite()
362//     }
363// }
364
365// impl<T: Signed> Size2D<T> {
366//     /// Computes the absolute value of each component.
367//     ///
368//     /// For `f32` and `f64`, `NaN` will be returned for component if the component is `NaN`.
369//     ///
370//     /// For signed integers, `::MIN` will be returned for component if the component is `::MIN`.
371//     pub fn abs(self) -> Self {
372//         size2(self.width.abs(), self.height.abs())
373//     }
374
375//     /// Returns `true` if both components is positive and `false` any component is zero or negative.
376//     pub fn is_positive(self) -> bool {
377//         self.width.is_positive() && self.height.is_positive()
378//     }
379// }
380
381// impl<T: PartialOrd> Size2D<T> {
382//     /// Returns the size each component of which are minimum of this size and another.
383//     #[inline]
384//     pub fn min(self, other: Self) -> Self {
385//         size2(min(self.width, other.width), min(self.height, other.height))
386//     }
387
388//     /// Returns the size each component of which are maximum of this size and another.
389//     #[inline]
390//     pub fn max(self, other: Self) -> Self {
391//         size2(max(self.width, other.width), max(self.height, other.height))
392//     }
393
394//     /// Returns the size each component of which clamped by corresponding
395//     /// components of `start` and `end`.
396//     ///
397//     /// Shortcut for `self.max(start).min(end)`.
398//     #[inline]
399//     pub fn clamp(self, start: Self, end: Self) -> Self
400//     where
401//         T: Copy,
402//     {
403//         self.max(start).min(end)
404//     }
405
406//     // Returns true if this size is larger or equal to the other size in all dimensions.
407//     #[inline]
408//     pub fn contains(self, other: Self) -> bool {
409//         self.width >= other.width && self.height >= other.height
410//     }
411
412//     /// Returns vector with results of "greater then" operation on each component.
413//     pub fn greater_than(self, other: Self) -> BoolVector2D {
414//         BoolVector2D {
415//             x: self.width > other.width,
416//             y: self.height > other.height,
417//         }
418//     }
419
420//     /// Returns vector with results of "lower then" operation on each component.
421//     pub fn lower_than(self, other: Self) -> BoolVector2D {
422//         BoolVector2D {
423//             x: self.width < other.width,
424//             y: self.height < other.height,
425//         }
426//     }
427
428//     /// Returns `true` if any component of size is zero, negative, or NaN.
429//     pub fn is_empty(self) -> bool
430//     where
431//         T: Zero,
432//     {
433//         let zero = T::zero();
434//         // The condition is experessed this way so that we return true in
435//         // the presence of NaN.
436//         !(self.width > zero && self.height > zero)
437//     }
438// }
439
440// impl<T: PartialEq> Size2D<T> {
441//     /// Returns vector with results of "equal" operation on each component.
442//     pub fn equal(self, other: Self) -> BoolVector2D {
443//         BoolVector2D {
444//             x: self.width == other.width,
445//             y: self.height == other.height,
446//         }
447//     }
448
449//     /// Returns vector with results of "not equal" operation on each component.
450//     pub fn not_equal(self, other: Self) -> BoolVector2D {
451//         BoolVector2D {
452//             x: self.width != other.width,
453//             y: self.height != other.height,
454//         }
455//     }
456// }
457
458// impl<T: Round> Round for Size2D<T> {
459//     /// See [`Size2D::round()`](#method.round).
460//     #[inline]
461//     fn round(self) -> Self {
462//         self.round()
463//     }
464// }
465
466// impl<T: Ceil> Ceil for Size2D<T> {
467//     /// See [`Size2D::ceil()`](#method.ceil).
468//     #[inline]
469//     fn ceil(self) -> Self {
470//         self.ceil()
471//     }
472// }
473
474// impl<T: Floor> Floor for Size2D<T> {
475//     /// See [`Size2D::floor()`](#method.floor).
476//     #[inline]
477//     fn floor(self) -> Self {
478//         self.floor()
479//     }
480// }
481
482impl<T: Zero> Zero for Size2D<T> {
483    #[inline]
484    fn zero() -> Self {
485        Size2D::new(Zero::zero(), Zero::zero())
486    }
487}
488
489impl<T: Neg> Neg for Size2D<T> {
490    type Output = Size2D<T::Output>;
491
492    #[inline]
493    fn neg(self) -> Self::Output {
494        Size2D::new(-self.width, -self.height)
495    }
496}
497
498impl<T: Add> Add for Size2D<T> {
499    type Output = Size2D<T::Output>;
500
501    #[inline]
502    fn add(self, other: Self) -> Self::Output {
503        Size2D::new(self.width + other.width, self.height + other.height)
504    }
505}
506
507impl<T: Copy + Add<T, Output = T>> Add<&Self> for Size2D<T> {
508    type Output = Self;
509    fn add(self, other: &Self) -> Self {
510        Size2D::new(self.width + other.width, self.height + other.height)
511    }
512}
513
514impl<T: Add<Output = T> + Zero> Sum for Size2D<T> {
515    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
516        iter.fold(Self::zero(), Add::add)
517    }
518}
519
520// TODO:
521// impl<'a, T: 'a + Add<Output = T> + Copy + Zero: 'a> Sum<&'a Self> for Size2D<T> {
522//     fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
523//         iter.fold(Self::zero(), Add::add)
524//     }
525// }
526
527impl<T: AddAssign> AddAssign for Size2D<T> {
528    #[inline]
529    fn add_assign(&mut self, other: Self) {
530        self.width += other.width;
531        self.height += other.height;
532    }
533}
534
535impl<T: Sub> Sub for Size2D<T> {
536    type Output = Size2D<T::Output>;
537
538    #[inline]
539    fn sub(self, other: Self) -> Self::Output {
540        Size2D::new(self.width - other.width, self.height - other.height)
541    }
542}
543
544impl<T: SubAssign> SubAssign for Size2D<T> {
545    #[inline]
546    fn sub_assign(&mut self, other: Self) {
547        self.width -= other.width;
548        self.height -= other.height;
549    }
550}
551
552impl<T: Copy + Mul> Mul<T> for Size2D<T> {
553    type Output = Size2D<T::Output>;
554
555    #[inline]
556    fn mul(self, scale: T) -> Self::Output {
557        Size2D::new(self.width * scale, self.height * scale)
558    }
559}
560
561impl<T: Copy + MulAssign> MulAssign<T> for Size2D<T> {
562    #[inline]
563    fn mul_assign(&mut self, other: T) {
564        self.width *= other;
565        self.height *= other;
566    }
567}
568
569// impl<T: Copy + Mul> Mul<Scale<T>> for Size2D<T> {
570//     type Output = Size2D<T::Output>;
571
572//     #[inline]
573//     fn mul(self, scale: Scale<T>) -> Self::Output {
574//         Size2D::new(self.width * scale.0, self.height * scale.0)
575//     }
576// }
577
578// impl<T: Copy + MulAssign> MulAssign<Scale<T>> for Size2D<T> {
579//     #[inline]
580//     fn mul_assign(&mut self, other: Scale<T>) {
581//         *self *= other.0;
582//     }
583// }
584
585impl<T: Copy + Div> Div<T> for Size2D<T> {
586    type Output = Size2D<T::Output>;
587
588    #[inline]
589    fn div(self, scale: T) -> Self::Output {
590        Size2D::new(self.width / scale, self.height / scale)
591    }
592}
593
594impl<T: Copy + DivAssign> DivAssign<T> for Size2D<T> {
595    #[inline]
596    fn div_assign(&mut self, other: T) {
597        self.width /= other;
598        self.height /= other;
599    }
600}
601
602// impl<T: Copy + Div> Div<Scale<T>> for Size2D<T> {
603//     type Output = Size2D<T::Output>;
604
605//     #[inline]
606//     fn div(self, scale: Scale<T>) -> Self::Output {
607//         Size2D::new(self.width / scale.0, self.height / scale.0)
608//     }
609// }
610
611// impl<T: Copy + DivAssign> DivAssign<Scale<T>> for Size2D<T> {
612//     #[inline]
613//     fn div_assign(&mut self, other: Scale<T>) {
614//         *self /= other.0;
615//     }
616// }
617
618/// Shorthand for `Size2D::new(w, h)`.
619#[inline]
620pub const fn size2<T>(w: T, h: T) -> Size2D<T> {
621    Size2D::new(w, h)
622}
623
624#[cfg(feature = "mint")]
625impl<T> From<mint::Vector2<T>> for Size2D<T> {
626    #[inline]
627    fn from(v: mint::Vector2<T>) -> Self {
628        Size2D {
629            width: v.x,
630            height: v.y,
631            _unit: PhantomData,
632        }
633    }
634}
635#[cfg(feature = "mint")]
636impl<T> Into<mint::Vector2<T>> for Size2D<T> {
637    #[inline]
638    fn into(self) -> mint::Vector2<T> {
639        mint::Vector2 {
640            x: self.width,
641            y: self.height,
642        }
643    }
644}
645
646// impl<T> From<Vector2D<T>> for Size2D<T> {
647//     #[inline]
648//     fn from(v: Vector2D<T>) -> Self {
649//         size2(v.x, v.y)
650//     }
651// }
652
653impl<T> Into<[T; 2]> for Size2D<T> {
654    #[inline]
655    fn into(self) -> [T; 2] {
656        [self.width, self.height]
657    }
658}
659
660impl<T> From<[T; 2]> for Size2D<T> {
661    #[inline]
662    fn from([w, h]: [T; 2]) -> Self {
663        size2(w, h)
664    }
665}
666
667impl<T> Into<(T, T)> for Size2D<T> {
668    #[inline]
669    fn into(self) -> (T, T) {
670        (self.width, self.height)
671    }
672}
673
674impl<T> From<(T, T)> for Size2D<T> {
675    #[inline]
676    fn from(tuple: (T, T)) -> Self {
677        size2(tuple.0, tuple.1)
678    }
679}
680
681#[cfg(test)]
682mod size2d {
683    use crate::foundation::Size2D;
684    #[cfg(feature = "mint")]
685    use mint;
686
687    #[test]
688    pub fn test_area() {
689        let p = Size2D::new(1.5, 2.0);
690        assert_eq!(p.area(), 3.0);
691    }
692
693    #[cfg(feature = "mint")]
694    #[test]
695    pub fn test_mint() {
696        let s1 = Size2D::new(1.0, 2.0);
697        let sm: mint::Vector2<_> = s1.into();
698        let s2 = Size2D::from(sm);
699
700        assert_eq!(s1, s2);
701    }
702
703    mod ops {
704        use crate::foundation::Size2D;
705        // use crate::scale::Scale;
706
707        // pub enum Mm {}
708        // pub enum Cm {}
709
710        // pub type Size2DMm<T> = crate::Size2D<T, Mm>;
711        // pub type Size2DCm<T> = crate::Size2D<T, Cm>;
712
713        #[test]
714        pub fn test_neg() {
715            assert_eq!(-Size2D::new(1.0, 2.0), Size2D::new(-1.0, -2.0));
716            assert_eq!(-Size2D::new(0.0, 0.0), Size2D::new(-0.0, -0.0));
717            assert_eq!(-Size2D::new(-1.0, -2.0), Size2D::new(1.0, 2.0));
718        }
719
720        #[test]
721        pub fn test_add() {
722            let s1 = Size2D::new(1.0, 2.0);
723            let s2 = Size2D::new(3.0, 4.0);
724            assert_eq!(s1 + s2, Size2D::new(4.0, 6.0));
725            assert_eq!(s1 + &s2, Size2D::new(4.0, 6.0));
726
727            let s1 = Size2D::new(1.0, 2.0);
728            let s2 = Size2D::new(0.0, 0.0);
729            assert_eq!(s1 + s2, Size2D::new(1.0, 2.0));
730            assert_eq!(s1 + &s2, Size2D::new(1.0, 2.0));
731
732            let s1 = Size2D::new(1.0, 2.0);
733            let s2 = Size2D::new(-3.0, -4.0);
734            assert_eq!(s1 + s2, Size2D::new(-2.0, -2.0));
735            assert_eq!(s1 + &s2, Size2D::new(-2.0, -2.0));
736
737            let s1 = Size2D::new(0.0, 0.0);
738            let s2 = Size2D::new(0.0, 0.0);
739            assert_eq!(s1 + s2, Size2D::new(0.0, 0.0));
740            assert_eq!(s1 + &s2, Size2D::new(0.0, 0.0));
741        }
742
743        #[test]
744        pub fn test_add_assign() {
745            let mut s = Size2D::new(1.0, 2.0);
746            s += Size2D::new(3.0, 4.0);
747            assert_eq!(s, Size2D::new(4.0, 6.0));
748
749            let mut s = Size2D::new(1.0, 2.0);
750            s += Size2D::new(0.0, 0.0);
751            assert_eq!(s, Size2D::new(1.0, 2.0));
752
753            let mut s = Size2D::new(1.0, 2.0);
754            s += Size2D::new(-3.0, -4.0);
755            assert_eq!(s, Size2D::new(-2.0, -2.0));
756
757            let mut s = Size2D::new(0.0, 0.0);
758            s += Size2D::new(0.0, 0.0);
759            assert_eq!(s, Size2D::new(0.0, 0.0));
760        }
761
762        // #[test]
763        // pub fn test_sum() {
764        //     let sizes = [
765        //         Size2D::new(0.0, 1.0),
766        //         Size2D::new(1.0, 2.0),
767        //         Size2D::new(2.0, 3.0)
768        //     ];
769        //     let sum = Size2D::new(3.0, 6.0);
770        //     assert_eq!(sizes.iter().sum::<Size2D<_>>(), sum);
771        //     assert_eq!(sizes.into_iter().sum::<Size2D<_>>(), sum);
772        // }
773
774        #[test]
775        pub fn test_sub() {
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(-2.0, -2.0));
779
780            let s1 = Size2D::new(1.0, 2.0);
781            let s2 = Size2D::new(0.0, 0.0);
782            assert_eq!(s1 - s2, Size2D::new(1.0, 2.0));
783
784            let s1 = Size2D::new(1.0, 2.0);
785            let s2 = Size2D::new(-3.0, -4.0);
786            assert_eq!(s1 - s2, Size2D::new(4.0, 6.0));
787
788            let s1 = Size2D::new(0.0, 0.0);
789            let s2 = Size2D::new(0.0, 0.0);
790            assert_eq!(s1 - s2, Size2D::new(0.0, 0.0));
791        }
792
793        #[test]
794        pub fn test_sub_assign() {
795            let mut s = Size2D::new(1.0, 2.0);
796            s -= Size2D::new(3.0, 4.0);
797            assert_eq!(s, Size2D::new(-2.0, -2.0));
798
799            let mut s = Size2D::new(1.0, 2.0);
800            s -= Size2D::new(0.0, 0.0);
801            assert_eq!(s, Size2D::new(1.0, 2.0));
802
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(0.0, 0.0);
808            s -= Size2D::new(0.0, 0.0);
809            assert_eq!(s, Size2D::new(0.0, 0.0));
810        }
811
812        #[test]
813        pub fn test_mul_scalar() {
814            let s1: Size2D<f32> = Size2D::new(3.0, 5.0);
815
816            let result = s1 * 5.0;
817
818            assert_eq!(result, Size2D::new(15.0, 25.0));
819        }
820
821        #[test]
822        pub fn test_mul_assign_scalar() {
823            let mut s1 = Size2D::new(3.0, 5.0);
824
825            s1 *= 5.0;
826
827            assert_eq!(s1, Size2D::new(15.0, 25.0));
828        }
829
830        // #[test]
831        // pub fn test_mul_scale() {
832        //     let s1 = Size2DMm::new(1.0, 2.0);
833        //     let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
834
835        //     let result = s1 * cm_per_mm;
836
837        //     assert_eq!(result, Size2DCm::new(0.1, 0.2));
838        // }
839
840        // #[test]
841        // pub fn test_mul_assign_scale() {
842        //     let mut s1 = Size2DMm::new(1.0, 2.0);
843        //     let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);
844
845        //     s1 *= scale;
846
847        //     assert_eq!(s1, Size2DMm::new(0.1, 0.2));
848        // }
849
850        #[test]
851        pub fn test_div_scalar() {
852            let s1: Size2D<f32> = Size2D::new(15.0, 25.0);
853
854            let result = s1 / 5.0;
855
856            assert_eq!(result, Size2D::new(3.0, 5.0));
857        }
858
859        #[test]
860        pub fn test_div_assign_scalar() {
861            let mut s1: Size2D<f32> = Size2D::new(15.0, 25.0);
862
863            s1 /= 5.0;
864
865            assert_eq!(s1, Size2D::new(3.0, 5.0));
866        }
867
868        // #[test]
869        // pub fn test_div_scale() {
870        //     let s1 = Size2DCm::new(0.1, 0.2);
871        //     let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
872
873        //     let result = s1 / cm_per_mm;
874
875        //     assert_eq!(result, Size2DMm::new(1.0, 2.0));
876        // }
877
878        // #[test]
879        // pub fn test_div_assign_scale() {
880        //     let mut s1 = Size2DMm::new(0.1, 0.2);
881        //     let scale: Scale<f32, Mm, Mm> = Scale::new(0.1);
882
883        //     s1 /= scale;
884
885        //     assert_eq!(s1, Size2DMm::new(1.0, 2.0));
886        // }
887
888        // #[test]
889        // pub fn test_nan_empty() {
890        //     use std::f32::NAN;
891        //     assert!(Size2D::new(NAN, 2.0).is_empty());
892        //     assert!(Size2D::new(0.0, NAN).is_empty());
893        //     assert!(Size2D::new(NAN, -2.0).is_empty());
894        // }
895    }
896}