// Copyright 2014 The Servo Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A one-dimensional length, tagged with its units. use crate::approxeq::ApproxEq; use crate::num::Zero; use crate::scale::Scale; use crate::approxord::{max, min}; use crate::num::One; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; use core::iter::Sum; use core::marker::PhantomData; use core::ops::{Add, Div, Mul, Neg, Sub}; use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; use num_traits::{NumCast, Saturating}; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "bytemuck")] use bytemuck::{Zeroable, Pod}; /// A one-dimensional distance, with value represented by `T` and unit of measurement `Unit`. /// /// `T` can be any numeric type, for example a primitive type like `u64` or `f32`. /// /// `Unit` is not used in the representation of a `Length` value. It is used only at compile time /// to ensure that a `Length` stored with one unit is converted explicitly before being used in an /// expression that requires a different unit. It may be a type without values, such as an empty /// enum. /// /// You can multiply a `Length` by a `scale::Scale` to convert it from one unit to /// another. See the [`Scale`] docs for an example. /// /// [`Scale`]: struct.Scale.html #[repr(C)] pub struct Length(pub T, #[doc(hidden)] pub PhantomData); impl Clone for Length { fn clone(&self) -> Self { Length(self.0.clone(), PhantomData) } } impl Copy for Length {} #[cfg(feature = "serde")] impl<'de, T, U> Deserialize<'de> for Length where T: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { Ok(Length(Deserialize::deserialize(deserializer)?, PhantomData)) } } #[cfg(feature = "serde")] impl Serialize for Length where T: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.0.serialize(serializer) } } #[cfg(feature = "bytemuck")] unsafe impl Zeroable for Length {} #[cfg(feature = "bytemuck")] unsafe impl Pod for Length {} impl Length { /// Associate a value with a unit of measure. #[inline] pub const fn new(x: T) -> Self { Length(x, PhantomData) } } impl Length { /// Unpack the underlying value from the wrapper. pub fn get(self) -> T { self.0 } /// Cast the unit #[inline] pub fn cast_unit(self) -> Length { Length::new(self.0) } /// Linearly interpolate between this length and another length. /// /// # Example /// /// ```rust /// use euclid::default::Length; /// /// let from = Length::new(0.0); /// let to = Length::new(8.0); /// /// assert_eq!(from.lerp(to, -1.0), Length::new(-8.0)); /// assert_eq!(from.lerp(to, 0.0), Length::new( 0.0)); /// assert_eq!(from.lerp(to, 0.5), Length::new( 4.0)); /// assert_eq!(from.lerp(to, 1.0), Length::new( 8.0)); /// assert_eq!(from.lerp(to, 2.0), Length::new(16.0)); /// ``` #[inline] pub fn lerp(self, other: Self, t: T) -> Self where T: One + Sub + Mul + Add, { let one_t = T::one() - t.clone(); Length::new(one_t * self.0.clone() + t * other.0) } } impl Length { /// Returns minimum between this length and another length. #[inline] pub fn min(self, other: Self) -> Self { min(self, other) } /// Returns maximum between this length and another length. #[inline] pub fn max(self, other: Self) -> Self { max(self, other) } } impl Length { /// Cast from one numeric representation to another, preserving the units. #[inline] pub fn cast(self) -> Length { self.try_cast().unwrap() } /// Fallible cast from one numeric representation to another, preserving the units. pub fn try_cast(self) -> Option> { NumCast::from(self.0).map(Length::new) } } impl fmt::Debug for Length { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } impl Default for Length { #[inline] fn default() -> Self { Length::new(Default::default()) } } impl Hash for Length { fn hash(&self, h: &mut H) { self.0.hash(h); } } // length + length impl Add for Length { type Output = Length; fn add(self, other: Self) -> Self::Output { Length::new(self.0 + other.0) } } // length + &length impl Add<&Self> for Length { type Output = Length; fn add(self, other: &Self) -> Self::Output { Length::new(self.0 + other.0) } } // length_iter.copied().sum() impl + Zero, U> Sum for Length { fn sum>(iter: I) -> Self { iter.fold(Self::zero(), Add::add) } } // length_iter.sum() impl<'a, T: 'a + Add + Copy + Zero, U: 'a> Sum<&'a Self> for Length { fn sum>(iter: I) -> Self { iter.fold(Self::zero(), Add::add) } } // length += length impl AddAssign for Length { fn add_assign(&mut self, other: Self) { self.0 += other.0; } } // length - length impl Sub for Length { type Output = Length; fn sub(self, other: Length) -> Self::Output { Length::new(self.0 - other.0) } } // length -= length impl SubAssign for Length { fn sub_assign(&mut self, other: Self) { self.0 -= other.0; } } // Saturating length + length and length - length. impl Saturating for Length { fn saturating_add(self, other: Self) -> Self { Length::new(self.0.saturating_add(other.0)) } fn saturating_sub(self, other: Self) -> Self { Length::new(self.0.saturating_sub(other.0)) } } // length / length impl Div> for Length { type Output = Scale; #[inline] fn div(self, other: Length) -> Self::Output { Scale::new(self.0 / other.0) } } // length * scalar impl Mul for Length { type Output = Length; #[inline] fn mul(self, scale: T) -> Self::Output { Length::new(self.0 * scale) } } // length *= scalar impl, U> MulAssign for Length { #[inline] fn mul_assign(&mut self, scale: T) { *self = *self * scale } } // length / scalar impl Div for Length { type Output = Length; #[inline] fn div(self, scale: T) -> Self::Output { Length::new(self.0 / scale) } } // length /= scalar impl, U> DivAssign for Length { #[inline] fn div_assign(&mut self, scale: T) { *self = *self / scale } } // length * scaleFactor impl Mul> for Length { type Output = Length; #[inline] fn mul(self, scale: Scale) -> Self::Output { Length::new(self.0 * scale.0) } } // length / scaleFactor impl Div> for Length { type Output = Length; #[inline] fn div(self, scale: Scale) -> Self::Output { Length::new(self.0 / scale.0) } } // -length impl Neg for Length { type Output = Length; #[inline] fn neg(self) -> Self::Output { Length::new(-self.0) } } impl PartialEq for Length { fn eq(&self, other: &Self) -> bool { self.0.eq(&other.0) } } impl PartialOrd for Length { fn partial_cmp(&self, other: &Self) -> Option { self.0.partial_cmp(&other.0) } } impl Eq for Length {} impl Ord for Length { fn cmp(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) } } impl Zero for Length { #[inline] fn zero() -> Self { Length::new(Zero::zero()) } } impl> ApproxEq for Length { #[inline] fn approx_epsilon() -> T { T::approx_epsilon() } #[inline] fn approx_eq_eps(&self, other: &Length, approx_epsilon: &T) -> bool { self.0.approx_eq_eps(&other.0, approx_epsilon) } } #[cfg(test)] mod tests { use super::Length; use crate::num::Zero; use crate::scale::Scale; use core::f32::INFINITY; use num_traits::Saturating; enum Inch {} enum Mm {} enum Cm {} enum Second {} #[cfg(feature = "serde")] mod serde { use super::*; extern crate serde_test; use self::serde_test::assert_tokens; use self::serde_test::Token; #[test] fn test_length_serde() { let one_cm: Length = Length::new(10.0); assert_tokens(&one_cm, &[Token::F32(10.0)]); } } #[test] fn test_clone() { // A cloned Length is a separate length with the state matching the // original Length at the point it was cloned. let mut variable_length: Length = Length::new(12.0); let one_foot = variable_length.clone(); variable_length.0 = 24.0; assert_eq!(one_foot.get(), 12.0); assert_eq!(variable_length.get(), 24.0); } #[test] fn test_add() { let length1: Length = Length::new(250); let length2: Length = Length::new(5); assert_eq!((length1 + length2).get(), 255); assert_eq!((length1 + &length2).get(), 255); } #[test] fn test_sum() { type L = Length; let lengths = [L::new(1.0), L::new(2.0), L::new(3.0)]; assert_eq!(lengths.iter().sum::(), L::new(6.0)); } #[test] fn test_addassign() { let one_cm: Length = Length::new(10.0); let mut measurement: Length = Length::new(5.0); measurement += one_cm; assert_eq!(measurement.get(), 15.0); } #[test] fn test_sub() { let length1: Length = Length::new(250); let length2: Length = Length::new(5); let result = length1 - length2; assert_eq!(result.get(), 245); } #[test] fn test_subassign() { let one_cm: Length = Length::new(10.0); let mut measurement: Length = Length::new(5.0); measurement -= one_cm; assert_eq!(measurement.get(), -5.0); } #[test] fn test_saturating_add() { let length1: Length = Length::new(250); let length2: Length = Length::new(6); let result = length1.saturating_add(length2); assert_eq!(result.get(), 255); } #[test] fn test_saturating_sub() { let length1: Length = Length::new(5); let length2: Length = Length::new(10); let result = length1.saturating_sub(length2); assert_eq!(result.get(), 0); } #[test] fn test_division_by_length() { // Division results in a Scale from denominator units // to numerator units. let length: Length = Length::new(5.0); let duration: Length = Length::new(10.0); let result = length / duration; let expected: Scale = Scale::new(0.5); assert_eq!(result, expected); } #[test] fn test_multiplication() { let length_mm: Length = Length::new(10.0); let cm_per_mm: Scale = Scale::new(0.1); let result = length_mm * cm_per_mm; let expected: Length = Length::new(1.0); assert_eq!(result, expected); } #[test] fn test_multiplication_with_scalar() { let length_mm: Length = Length::new(10.0); let result = length_mm * 2.0; let expected: Length = Length::new(20.0); assert_eq!(result, expected); } #[test] fn test_multiplication_assignment() { let mut length: Length = Length::new(10.0); length *= 2.0; let expected: Length = Length::new(20.0); assert_eq!(length, expected); } #[test] fn test_division_by_scalefactor() { let length: Length = Length::new(5.0); let cm_per_second: Scale = Scale::new(10.0); let result = length / cm_per_second; let expected: Length = Length::new(0.5); assert_eq!(result, expected); } #[test] fn test_division_by_scalar() { let length: Length = Length::new(5.0); let result = length / 2.0; let expected: Length = Length::new(2.5); assert_eq!(result, expected); } #[test] fn test_division_assignment() { let mut length: Length = Length::new(10.0); length /= 2.0; let expected: Length = Length::new(5.0); assert_eq!(length, expected); } #[test] fn test_negation() { let length: Length = Length::new(5.0); let result = -length; let expected: Length = Length::new(-5.0); assert_eq!(result, expected); } #[test] fn test_cast() { let length_as_i32: Length = Length::new(5); let result: Length = length_as_i32.cast(); let length_as_f32: Length = Length::new(5.0); assert_eq!(result, length_as_f32); } #[test] fn test_equality() { let length_5_point_0: Length = Length::new(5.0); let length_5_point_1: Length = Length::new(5.1); let length_0_point_1: Length = Length::new(0.1); assert!(length_5_point_0 == length_5_point_1 - length_0_point_1); assert!(length_5_point_0 != length_5_point_1); } #[test] fn test_order() { let length_5_point_0: Length = Length::new(5.0); let length_5_point_1: Length = Length::new(5.1); let length_0_point_1: Length = Length::new(0.1); assert!(length_5_point_0 < length_5_point_1); assert!(length_5_point_0 <= length_5_point_1); assert!(length_5_point_0 <= length_5_point_1 - length_0_point_1); assert!(length_5_point_1 > length_5_point_0); assert!(length_5_point_1 >= length_5_point_0); assert!(length_5_point_0 >= length_5_point_1 - length_0_point_1); } #[test] fn test_zero_add() { type LengthCm = Length; let length: LengthCm = Length::new(5.0); let result = length - LengthCm::zero(); assert_eq!(result, length); } #[test] fn test_zero_division() { type LengthCm = Length; let length: LengthCm = Length::new(5.0); let length_zero: LengthCm = Length::zero(); let result = length / length_zero; let expected: Scale = Scale::new(INFINITY); assert_eq!(result, expected); } }