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