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