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}