1 use crate::{trim_f64, Duration, Speed}; 2 use serde::{Deserialize, Serialize}; 3 use std::{cmp, f64, fmt, ops}; 4 5 // In meters. Can be negative. 6 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] 7 pub struct Distance(f64); 8 9 // By construction, Distance is a finite f64 with trimmed precision. 10 impl Eq for Distance {} 11 impl Ord for Distance { cmp(&self, other: &Distance) -> cmp::Ordering12 fn cmp(&self, other: &Distance) -> cmp::Ordering { 13 self.partial_cmp(other).unwrap() 14 } 15 } 16 17 impl Distance { 18 pub const ZERO: Distance = Distance::const_meters(0.0); 19 meters(value: f64) -> Distance20 pub fn meters(value: f64) -> Distance { 21 if !value.is_finite() { 22 panic!("Bad Distance {}", value); 23 } 24 25 Distance(trim_f64(value)) 26 } 27 28 // TODO Can't panic inside a const fn, seemingly. Don't pass in anything bad! const_meters(value: f64) -> Distance29 pub const fn const_meters(value: f64) -> Distance { 30 Distance(value) 31 } 32 inches(value: f64) -> Distance33 pub fn inches(value: f64) -> Distance { 34 Distance::meters(0.0254 * value) 35 } 36 miles(value: f64) -> Distance37 pub fn miles(value: f64) -> Distance { 38 Distance::meters(1609.34 * value) 39 } 40 centimeters(value: usize) -> Distance41 pub fn centimeters(value: usize) -> Distance { 42 Distance::meters((value as f64) / 100.0) 43 } 44 abs(self) -> Distance45 pub fn abs(self) -> Distance { 46 if self.0 > 0.0 { 47 self 48 } else { 49 Distance(-self.0) 50 } 51 } 52 sqrt(self) -> Distance53 pub fn sqrt(self) -> Distance { 54 Distance::meters(self.0.sqrt()) 55 } 56 57 // TODO Remove if possible. inner_meters(self) -> f6458 pub fn inner_meters(self) -> f64 { 59 self.0 60 } 61 62 // TODO Store a bit in Maps to mark if they're in the US or not, plumb here to use meters describe_rounded(self) -> String63 pub fn describe_rounded(self) -> String { 64 let feet = self.0 * 3.28084; 65 let miles = feet / 5280.0; 66 if miles >= 0.1 { 67 format!("{} miles", (miles * 10.0).round() / 10.0) 68 } else { 69 format!("{} ft", feet.round()) 70 } 71 } 72 } 73 74 impl fmt::Display for Distance { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 76 // TODO This is harder to localize 77 write!(f, "{}m", self.0) 78 } 79 } 80 81 impl ops::Add for Distance { 82 type Output = Distance; 83 add(self, other: Distance) -> Distance84 fn add(self, other: Distance) -> Distance { 85 Distance::meters(self.0 + other.0) 86 } 87 } 88 89 impl ops::AddAssign for Distance { add_assign(&mut self, other: Distance)90 fn add_assign(&mut self, other: Distance) { 91 *self = *self + other; 92 } 93 } 94 95 impl ops::Sub for Distance { 96 type Output = Distance; 97 sub(self, other: Distance) -> Distance98 fn sub(self, other: Distance) -> Distance { 99 Distance::meters(self.0 - other.0) 100 } 101 } 102 103 impl ops::Neg for Distance { 104 type Output = Distance; 105 neg(self) -> Distance106 fn neg(self) -> Distance { 107 Distance::meters(-self.0) 108 } 109 } 110 111 impl ops::SubAssign for Distance { sub_assign(&mut self, other: Distance)112 fn sub_assign(&mut self, other: Distance) { 113 *self = *self - other; 114 } 115 } 116 117 impl ops::Mul<f64> for Distance { 118 type Output = Distance; 119 mul(self, scalar: f64) -> Distance120 fn mul(self, scalar: f64) -> Distance { 121 Distance::meters(self.0 * scalar) 122 } 123 } 124 125 impl ops::Mul<Distance> for f64 { 126 type Output = Distance; 127 mul(self, other: Distance) -> Distance128 fn mul(self, other: Distance) -> Distance { 129 Distance::meters(self * other.0) 130 } 131 } 132 133 impl ops::Div<Distance> for Distance { 134 type Output = f64; 135 div(self, other: Distance) -> f64136 fn div(self, other: Distance) -> f64 { 137 if other == Distance::ZERO { 138 panic!("Can't divide {} / {}", self, other); 139 } 140 self.0 / other.0 141 } 142 } 143 144 impl ops::Div<f64> for Distance { 145 type Output = Distance; 146 div(self, scalar: f64) -> Distance147 fn div(self, scalar: f64) -> Distance { 148 if scalar == 0.0 { 149 panic!("Can't divide {} / {}", self, scalar); 150 } 151 Distance::meters(self.0 / scalar) 152 } 153 } 154 155 impl ops::Div<Speed> for Distance { 156 type Output = Duration; 157 div(self, other: Speed) -> Duration158 fn div(self, other: Speed) -> Duration { 159 if other == Speed::ZERO { 160 panic!("Can't divide {} / {}", self, other); 161 } 162 Duration::seconds(self.0 / other.inner_meters_per_second()) 163 } 164 } 165 166 impl std::iter::Sum for Distance { sum<I>(iter: I) -> Distance where I: Iterator<Item = Distance>,167 fn sum<I>(iter: I) -> Distance 168 where 169 I: Iterator<Item = Distance>, 170 { 171 let mut sum = Distance::ZERO; 172 for x in iter { 173 sum += x; 174 } 175 sum 176 } 177 } 178 179 impl Default for Distance { default() -> Distance180 fn default() -> Distance { 181 Distance::ZERO 182 } 183 } 184