| 1 | // Copyright 2014 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 | //! A one-dimensional length, tagged with its units. |
| 10 | |
| 11 | use crate::approxeq::ApproxEq; |
| 12 | use crate::approxord::{max, min}; |
| 13 | use crate::num::Zero; |
| 14 | use crate::scale::Scale; |
| 15 | |
| 16 | use crate::num::One; |
| 17 | #[cfg (feature = "bytemuck" )] |
| 18 | use bytemuck::{Pod, Zeroable}; |
| 19 | use core::cmp::Ordering; |
| 20 | use core::fmt; |
| 21 | use core::hash::{Hash, Hasher}; |
| 22 | use core::iter::Sum; |
| 23 | use core::marker::PhantomData; |
| 24 | use core::ops::{Add, Div, Mul, Neg, Sub}; |
| 25 | use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; |
| 26 | use num_traits::{NumCast, Saturating}; |
| 27 | #[cfg (feature = "serde" )] |
| 28 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
| 29 | |
| 30 | /// A one-dimensional distance, with value represented by `T` and unit of measurement `Unit`. |
| 31 | /// |
| 32 | /// `T` can be any numeric type, for example a primitive type like `u64` or `f32`. |
| 33 | /// |
| 34 | /// `Unit` is not used in the representation of a `Length` value. It is used only at compile time |
| 35 | /// to ensure that a `Length` stored with one unit is converted explicitly before being used in an |
| 36 | /// expression that requires a different unit. It may be a type without values, such as an empty |
| 37 | /// enum. |
| 38 | /// |
| 39 | /// You can multiply a `Length` by a [`Scale`] to convert it from one unit to |
| 40 | /// another. See the [`Scale`] docs for an example. |
| 41 | #[repr (C)] |
| 42 | pub struct Length<T, Unit>(pub T, #[doc (hidden)] pub PhantomData<Unit>); |
| 43 | |
| 44 | impl<T: Clone, U> Clone for Length<T, U> { |
| 45 | fn clone(&self) -> Self { |
| 46 | Length(self.0.clone(), PhantomData) |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | impl<T: Copy, U> Copy for Length<T, U> {} |
| 51 | |
| 52 | #[cfg (feature = "serde" )] |
| 53 | impl<'de, T, U> Deserialize<'de> for Length<T, U> |
| 54 | where |
| 55 | T: Deserialize<'de>, |
| 56 | { |
| 57 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 58 | where |
| 59 | D: Deserializer<'de>, |
| 60 | { |
| 61 | Ok(Length(Deserialize::deserialize(deserializer)?, PhantomData)) |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | #[cfg (feature = "serde" )] |
| 66 | impl<T, U> Serialize for Length<T, U> |
| 67 | where |
| 68 | T: Serialize, |
| 69 | { |
| 70 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 71 | where |
| 72 | S: Serializer, |
| 73 | { |
| 74 | self.0.serialize(serializer) |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | #[cfg (feature = "arbitrary" )] |
| 79 | impl<'a, T, U> arbitrary::Arbitrary<'a> for Length<T, U> |
| 80 | where |
| 81 | T: arbitrary::Arbitrary<'a>, |
| 82 | { |
| 83 | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
| 84 | Ok(Length(arbitrary::Arbitrary::arbitrary(u)?, PhantomData)) |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | #[cfg (feature = "bytemuck" )] |
| 89 | unsafe impl<T: Zeroable, U> Zeroable for Length<T, U> {} |
| 90 | |
| 91 | #[cfg (feature = "bytemuck" )] |
| 92 | unsafe impl<T: Pod, U: 'static> Pod for Length<T, U> {} |
| 93 | |
| 94 | impl<T, U> Length<T, U> { |
| 95 | /// Associate a value with a unit of measure. |
| 96 | #[inline ] |
| 97 | pub const fn new(x: T) -> Self { |
| 98 | Length(x, PhantomData) |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | impl<T: Clone, U> Length<T, U> { |
| 103 | /// Unpack the underlying value from the wrapper. |
| 104 | pub fn get(self) -> T { |
| 105 | self.0 |
| 106 | } |
| 107 | |
| 108 | /// Cast the unit |
| 109 | #[inline ] |
| 110 | pub fn cast_unit<V>(self) -> Length<T, V> { |
| 111 | Length::new(self.0) |
| 112 | } |
| 113 | |
| 114 | /// Linearly interpolate between this length and another length. |
| 115 | /// |
| 116 | /// # Example |
| 117 | /// |
| 118 | /// ```rust |
| 119 | /// use euclid::default::Length; |
| 120 | /// |
| 121 | /// let from = Length::new(0.0); |
| 122 | /// let to = Length::new(8.0); |
| 123 | /// |
| 124 | /// assert_eq!(from.lerp(to, -1.0), Length::new(-8.0)); |
| 125 | /// assert_eq!(from.lerp(to, 0.0), Length::new( 0.0)); |
| 126 | /// assert_eq!(from.lerp(to, 0.5), Length::new( 4.0)); |
| 127 | /// assert_eq!(from.lerp(to, 1.0), Length::new( 8.0)); |
| 128 | /// assert_eq!(from.lerp(to, 2.0), Length::new(16.0)); |
| 129 | /// ``` |
| 130 | #[inline ] |
| 131 | pub fn lerp(self, other: Self, t: T) -> Self |
| 132 | where |
| 133 | T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>, |
| 134 | { |
| 135 | let one_t = T::one() - t.clone(); |
| 136 | Length::new(one_t * self.0.clone() + t * other.0) |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | impl<T: PartialOrd, U> Length<T, U> { |
| 141 | /// Returns minimum between this length and another length. |
| 142 | #[inline ] |
| 143 | pub fn min(self, other: Self) -> Self { |
| 144 | min(self, y:other) |
| 145 | } |
| 146 | |
| 147 | /// Returns maximum between this length and another length. |
| 148 | #[inline ] |
| 149 | pub fn max(self, other: Self) -> Self { |
| 150 | max(self, y:other) |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | impl<T: NumCast + Clone, U> Length<T, U> { |
| 155 | /// Cast from one numeric representation to another, preserving the units. |
| 156 | #[inline ] |
| 157 | pub fn cast<NewT: NumCast>(self) -> Length<NewT, U> { |
| 158 | self.try_cast().unwrap() |
| 159 | } |
| 160 | |
| 161 | /// Fallible cast from one numeric representation to another, preserving the units. |
| 162 | pub fn try_cast<NewT: NumCast>(self) -> Option<Length<NewT, U>> { |
| 163 | NumCast::from(self.0).map(Length::new) |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | impl<T: fmt::Debug, U> fmt::Debug for Length<T, U> { |
| 168 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 169 | self.0.fmt(f) |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | impl<T: Default, U> Default for Length<T, U> { |
| 174 | #[inline ] |
| 175 | fn default() -> Self { |
| 176 | Length::new(Default::default()) |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | impl<T: Hash, U> Hash for Length<T, U> { |
| 181 | fn hash<H: Hasher>(&self, h: &mut H) { |
| 182 | self.0.hash(state:h); |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | // length + length |
| 187 | impl<T: Add, U> Add for Length<T, U> { |
| 188 | type Output = Length<T::Output, U>; |
| 189 | |
| 190 | fn add(self, other: Self) -> Self::Output { |
| 191 | Length::new(self.0 + other.0) |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | // length + &length |
| 196 | impl<T: Add + Copy, U> Add<&Self> for Length<T, U> { |
| 197 | type Output = Length<T::Output, U>; |
| 198 | |
| 199 | fn add(self, other: &Self) -> Self::Output { |
| 200 | Length::new(self.0 + other.0) |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | // length_iter.copied().sum() |
| 205 | impl<T: Add<Output = T> + Zero, U> Sum for Length<T, U> { |
| 206 | fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { |
| 207 | iter.fold(Self::zero(), f:Add::add) |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | // length_iter.sum() |
| 212 | impl<'a, T: 'a + Add<Output = T> + Copy + Zero, U: 'a> Sum<&'a Self> for Length<T, U> { |
| 213 | fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self { |
| 214 | iter.fold(Self::zero(), f:Add::add) |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | // length += length |
| 219 | impl<T: AddAssign, U> AddAssign for Length<T, U> { |
| 220 | fn add_assign(&mut self, other: Self) { |
| 221 | self.0 += other.0; |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | // length - length |
| 226 | impl<T: Sub, U> Sub for Length<T, U> { |
| 227 | type Output = Length<T::Output, U>; |
| 228 | |
| 229 | fn sub(self, other: Length<T, U>) -> Self::Output { |
| 230 | Length::new(self.0 - other.0) |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | // length -= length |
| 235 | impl<T: SubAssign, U> SubAssign for Length<T, U> { |
| 236 | fn sub_assign(&mut self, other: Self) { |
| 237 | self.0 -= other.0; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | // Saturating length + length and length - length. |
| 242 | impl<T: Saturating, U> Saturating for Length<T, U> { |
| 243 | fn saturating_add(self, other: Self) -> Self { |
| 244 | Length::new(self.0.saturating_add(other.0)) |
| 245 | } |
| 246 | |
| 247 | fn saturating_sub(self, other: Self) -> Self { |
| 248 | Length::new(self.0.saturating_sub(other.0)) |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | // length / length |
| 253 | impl<Src, Dst, T: Div> Div<Length<T, Src>> for Length<T, Dst> { |
| 254 | type Output = Scale<T::Output, Src, Dst>; |
| 255 | |
| 256 | #[inline ] |
| 257 | fn div(self, other: Length<T, Src>) -> Self::Output { |
| 258 | Scale::new(self.0 / other.0) |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | // length * scalar |
| 263 | impl<T: Mul, U> Mul<T> for Length<T, U> { |
| 264 | type Output = Length<T::Output, U>; |
| 265 | |
| 266 | #[inline ] |
| 267 | fn mul(self, scale: T) -> Self::Output { |
| 268 | Length::new(self.0 * scale) |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | // length *= scalar |
| 273 | impl<T: Copy + Mul<T, Output = T>, U> MulAssign<T> for Length<T, U> { |
| 274 | #[inline ] |
| 275 | fn mul_assign(&mut self, scale: T) { |
| 276 | *self = *self * scale |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | // length / scalar |
| 281 | impl<T: Div, U> Div<T> for Length<T, U> { |
| 282 | type Output = Length<T::Output, U>; |
| 283 | |
| 284 | #[inline ] |
| 285 | fn div(self, scale: T) -> Self::Output { |
| 286 | Length::new(self.0 / scale) |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | // length /= scalar |
| 291 | impl<T: Copy + Div<T, Output = T>, U> DivAssign<T> for Length<T, U> { |
| 292 | #[inline ] |
| 293 | fn div_assign(&mut self, scale: T) { |
| 294 | *self = *self / scale |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | // length * scaleFactor |
| 299 | impl<Src, Dst, T: Mul> Mul<Scale<T, Src, Dst>> for Length<T, Src> { |
| 300 | type Output = Length<T::Output, Dst>; |
| 301 | |
| 302 | #[inline ] |
| 303 | fn mul(self, scale: Scale<T, Src, Dst>) -> Self::Output { |
| 304 | Length::new(self.0 * scale.0) |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | // length / scaleFactor |
| 309 | impl<Src, Dst, T: Div> Div<Scale<T, Src, Dst>> for Length<T, Dst> { |
| 310 | type Output = Length<T::Output, Src>; |
| 311 | |
| 312 | #[inline ] |
| 313 | fn div(self, scale: Scale<T, Src, Dst>) -> Self::Output { |
| 314 | Length::new(self.0 / scale.0) |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | // -length |
| 319 | impl<U, T: Neg> Neg for Length<T, U> { |
| 320 | type Output = Length<T::Output, U>; |
| 321 | |
| 322 | #[inline ] |
| 323 | fn neg(self) -> Self::Output { |
| 324 | Length::new(-self.0) |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | impl<T: PartialEq, U> PartialEq for Length<T, U> { |
| 329 | fn eq(&self, other: &Self) -> bool { |
| 330 | self.0.eq(&other.0) |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | impl<T: PartialOrd, U> PartialOrd for Length<T, U> { |
| 335 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
| 336 | self.0.partial_cmp(&other.0) |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | impl<T: Eq, U> Eq for Length<T, U> {} |
| 341 | |
| 342 | impl<T: Ord, U> Ord for Length<T, U> { |
| 343 | fn cmp(&self, other: &Self) -> Ordering { |
| 344 | self.0.cmp(&other.0) |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | impl<T: Zero, U> Zero for Length<T, U> { |
| 349 | #[inline ] |
| 350 | fn zero() -> Self { |
| 351 | Length::new(Zero::zero()) |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | impl<U, T: ApproxEq<T>> ApproxEq<T> for Length<T, U> { |
| 356 | #[inline ] |
| 357 | fn approx_epsilon() -> T { |
| 358 | T::approx_epsilon() |
| 359 | } |
| 360 | |
| 361 | #[inline ] |
| 362 | fn approx_eq_eps(&self, other: &Length<T, U>, approx_epsilon: &T) -> bool { |
| 363 | self.0.approx_eq_eps(&other.0, approx_epsilon) |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | #[cfg (test)] |
| 368 | mod tests { |
| 369 | use super::Length; |
| 370 | use crate::num::Zero; |
| 371 | |
| 372 | use crate::scale::Scale; |
| 373 | use core::f32::INFINITY; |
| 374 | use num_traits::Saturating; |
| 375 | |
| 376 | enum Inch {} |
| 377 | enum Mm {} |
| 378 | enum Cm {} |
| 379 | enum Second {} |
| 380 | |
| 381 | #[cfg (feature = "serde" )] |
| 382 | mod serde { |
| 383 | use super::*; |
| 384 | |
| 385 | extern crate serde_test; |
| 386 | use self::serde_test::assert_tokens; |
| 387 | use self::serde_test::Token; |
| 388 | |
| 389 | #[test ] |
| 390 | fn test_length_serde() { |
| 391 | let one_cm: Length<f32, Mm> = Length::new(10.0); |
| 392 | |
| 393 | assert_tokens(&one_cm, &[Token::F32(10.0)]); |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | #[test ] |
| 398 | fn test_clone() { |
| 399 | // A cloned Length is a separate length with the state matching the |
| 400 | // original Length at the point it was cloned. |
| 401 | let mut variable_length: Length<f32, Inch> = Length::new(12.0); |
| 402 | |
| 403 | let one_foot = variable_length.clone(); |
| 404 | variable_length.0 = 24.0; |
| 405 | |
| 406 | assert_eq!(one_foot.get(), 12.0); |
| 407 | assert_eq!(variable_length.get(), 24.0); |
| 408 | } |
| 409 | |
| 410 | #[test ] |
| 411 | fn test_add() { |
| 412 | let length1: Length<u8, Mm> = Length::new(250); |
| 413 | let length2: Length<u8, Mm> = Length::new(5); |
| 414 | |
| 415 | assert_eq!((length1 + length2).get(), 255); |
| 416 | assert_eq!((length1 + &length2).get(), 255); |
| 417 | } |
| 418 | |
| 419 | #[test ] |
| 420 | fn test_sum() { |
| 421 | type L = Length<f32, Mm>; |
| 422 | let lengths = [L::new(1.0), L::new(2.0), L::new(3.0)]; |
| 423 | |
| 424 | assert_eq!(lengths.iter().sum::<L>(), L::new(6.0)); |
| 425 | } |
| 426 | |
| 427 | #[test ] |
| 428 | fn test_addassign() { |
| 429 | let one_cm: Length<f32, Mm> = Length::new(10.0); |
| 430 | let mut measurement: Length<f32, Mm> = Length::new(5.0); |
| 431 | |
| 432 | measurement += one_cm; |
| 433 | |
| 434 | assert_eq!(measurement.get(), 15.0); |
| 435 | } |
| 436 | |
| 437 | #[test ] |
| 438 | fn test_sub() { |
| 439 | let length1: Length<u8, Mm> = Length::new(250); |
| 440 | let length2: Length<u8, Mm> = Length::new(5); |
| 441 | |
| 442 | let result = length1 - length2; |
| 443 | |
| 444 | assert_eq!(result.get(), 245); |
| 445 | } |
| 446 | |
| 447 | #[test ] |
| 448 | fn test_subassign() { |
| 449 | let one_cm: Length<f32, Mm> = Length::new(10.0); |
| 450 | let mut measurement: Length<f32, Mm> = Length::new(5.0); |
| 451 | |
| 452 | measurement -= one_cm; |
| 453 | |
| 454 | assert_eq!(measurement.get(), -5.0); |
| 455 | } |
| 456 | |
| 457 | #[test ] |
| 458 | fn test_saturating_add() { |
| 459 | let length1: Length<u8, Mm> = Length::new(250); |
| 460 | let length2: Length<u8, Mm> = Length::new(6); |
| 461 | |
| 462 | let result = length1.saturating_add(length2); |
| 463 | |
| 464 | assert_eq!(result.get(), 255); |
| 465 | } |
| 466 | |
| 467 | #[test ] |
| 468 | fn test_saturating_sub() { |
| 469 | let length1: Length<u8, Mm> = Length::new(5); |
| 470 | let length2: Length<u8, Mm> = Length::new(10); |
| 471 | |
| 472 | let result = length1.saturating_sub(length2); |
| 473 | |
| 474 | assert_eq!(result.get(), 0); |
| 475 | } |
| 476 | |
| 477 | #[test ] |
| 478 | fn test_division_by_length() { |
| 479 | // Division results in a Scale from denominator units |
| 480 | // to numerator units. |
| 481 | let length: Length<f32, Cm> = Length::new(5.0); |
| 482 | let duration: Length<f32, Second> = Length::new(10.0); |
| 483 | |
| 484 | let result = length / duration; |
| 485 | |
| 486 | let expected: Scale<f32, Second, Cm> = Scale::new(0.5); |
| 487 | assert_eq!(result, expected); |
| 488 | } |
| 489 | |
| 490 | #[test ] |
| 491 | fn test_multiplication() { |
| 492 | let length_mm: Length<f32, Mm> = Length::new(10.0); |
| 493 | let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1); |
| 494 | |
| 495 | let result = length_mm * cm_per_mm; |
| 496 | |
| 497 | let expected: Length<f32, Cm> = Length::new(1.0); |
| 498 | assert_eq!(result, expected); |
| 499 | } |
| 500 | |
| 501 | #[test ] |
| 502 | fn test_multiplication_with_scalar() { |
| 503 | let length_mm: Length<f32, Mm> = Length::new(10.0); |
| 504 | |
| 505 | let result = length_mm * 2.0; |
| 506 | |
| 507 | let expected: Length<f32, Mm> = Length::new(20.0); |
| 508 | assert_eq!(result, expected); |
| 509 | } |
| 510 | |
| 511 | #[test ] |
| 512 | fn test_multiplication_assignment() { |
| 513 | let mut length: Length<f32, Mm> = Length::new(10.0); |
| 514 | |
| 515 | length *= 2.0; |
| 516 | |
| 517 | let expected: Length<f32, Mm> = Length::new(20.0); |
| 518 | assert_eq!(length, expected); |
| 519 | } |
| 520 | |
| 521 | #[test ] |
| 522 | fn test_division_by_scalefactor() { |
| 523 | let length: Length<f32, Cm> = Length::new(5.0); |
| 524 | let cm_per_second: Scale<f32, Second, Cm> = Scale::new(10.0); |
| 525 | |
| 526 | let result = length / cm_per_second; |
| 527 | |
| 528 | let expected: Length<f32, Second> = Length::new(0.5); |
| 529 | assert_eq!(result, expected); |
| 530 | } |
| 531 | |
| 532 | #[test ] |
| 533 | fn test_division_by_scalar() { |
| 534 | let length: Length<f32, Cm> = Length::new(5.0); |
| 535 | |
| 536 | let result = length / 2.0; |
| 537 | |
| 538 | let expected: Length<f32, Cm> = Length::new(2.5); |
| 539 | assert_eq!(result, expected); |
| 540 | } |
| 541 | |
| 542 | #[test ] |
| 543 | fn test_division_assignment() { |
| 544 | let mut length: Length<f32, Mm> = Length::new(10.0); |
| 545 | |
| 546 | length /= 2.0; |
| 547 | |
| 548 | let expected: Length<f32, Mm> = Length::new(5.0); |
| 549 | assert_eq!(length, expected); |
| 550 | } |
| 551 | |
| 552 | #[test ] |
| 553 | fn test_negation() { |
| 554 | let length: Length<f32, Cm> = Length::new(5.0); |
| 555 | |
| 556 | let result = -length; |
| 557 | |
| 558 | let expected: Length<f32, Cm> = Length::new(-5.0); |
| 559 | assert_eq!(result, expected); |
| 560 | } |
| 561 | |
| 562 | #[test ] |
| 563 | fn test_cast() { |
| 564 | let length_as_i32: Length<i32, Cm> = Length::new(5); |
| 565 | |
| 566 | let result: Length<f32, Cm> = length_as_i32.cast(); |
| 567 | |
| 568 | let length_as_f32: Length<f32, Cm> = Length::new(5.0); |
| 569 | assert_eq!(result, length_as_f32); |
| 570 | } |
| 571 | |
| 572 | #[test ] |
| 573 | fn test_equality() { |
| 574 | let length_5_point_0: Length<f32, Cm> = Length::new(5.0); |
| 575 | let length_5_point_1: Length<f32, Cm> = Length::new(5.1); |
| 576 | let length_0_point_1: Length<f32, Cm> = Length::new(0.1); |
| 577 | |
| 578 | assert!(length_5_point_0 == length_5_point_1 - length_0_point_1); |
| 579 | assert!(length_5_point_0 != length_5_point_1); |
| 580 | } |
| 581 | |
| 582 | #[test ] |
| 583 | fn test_order() { |
| 584 | let length_5_point_0: Length<f32, Cm> = Length::new(5.0); |
| 585 | let length_5_point_1: Length<f32, Cm> = Length::new(5.1); |
| 586 | let length_0_point_1: Length<f32, Cm> = Length::new(0.1); |
| 587 | |
| 588 | assert!(length_5_point_0 < length_5_point_1); |
| 589 | assert!(length_5_point_0 <= length_5_point_1); |
| 590 | assert!(length_5_point_0 <= length_5_point_1 - length_0_point_1); |
| 591 | assert!(length_5_point_1 > length_5_point_0); |
| 592 | assert!(length_5_point_1 >= length_5_point_0); |
| 593 | assert!(length_5_point_0 >= length_5_point_1 - length_0_point_1); |
| 594 | } |
| 595 | |
| 596 | #[test ] |
| 597 | fn test_zero_add() { |
| 598 | type LengthCm = Length<f32, Cm>; |
| 599 | let length: LengthCm = Length::new(5.0); |
| 600 | |
| 601 | let result = length - LengthCm::zero(); |
| 602 | |
| 603 | assert_eq!(result, length); |
| 604 | } |
| 605 | |
| 606 | #[test ] |
| 607 | fn test_zero_division() { |
| 608 | type LengthCm = Length<f32, Cm>; |
| 609 | let length: LengthCm = Length::new(5.0); |
| 610 | let length_zero: LengthCm = Length::zero(); |
| 611 | |
| 612 | let result = length / length_zero; |
| 613 | |
| 614 | let expected: Scale<f32, Cm, Cm> = Scale::new(INFINITY); |
| 615 | assert_eq!(result, expected); |
| 616 | } |
| 617 | } |
| 618 | |