measurements/
acceleration.rs

1//! Types and constants for handling acceleration.
2
3use super::length;
4use super::measurement::*;
5#[cfg(feature = "from_str")]
6use regex::Regex;
7#[cfg(feature = "from_str")]
8use std::str::FromStr;
9
10/// The `Acceleration` struct can be used to deal with Accelerations in a common way.
11/// Common metric and imperial units are supported.
12///
13/// # Example
14///
15/// ```
16/// extern crate measurements;
17/// use measurements::{Acceleration, Length, Speed};
18/// use std::time::Duration;
19///
20/// fn main() {
21///     // Standing quarter mile in 10.0 dead, at 120.0 mph
22///     let track = Length::from_miles(0.25);
23///     let finish = Speed::from_miles_per_hour(120.0);
24///     let time = Duration::new(10, 0);
25///     let accel: Acceleration = finish / time;
26///     println!("You accelerated over {} at an average of {}", track, accel);
27///}
28/// ```
29#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
30#[derive(Copy, Clone, Debug)]
31pub struct Acceleration {
32    meters_per_second_per_second: f64,
33}
34
35impl Acceleration {
36    /// Create a new Acceleration from a floating point value in meters per second per second
37    pub fn from_meters_per_second_per_second(meters_per_second_per_second: f64) -> Acceleration {
38        Acceleration {
39            meters_per_second_per_second,
40        }
41    }
42
43    /// Create a new Acceleration from a floating point value in metres per second per second
44    pub fn from_metres_per_second_per_second(metres_per_second_per_second: f64) -> Acceleration {
45        Acceleration::from_meters_per_second_per_second(metres_per_second_per_second)
46    }
47
48    /// Create a new Acceleration from a floating point value in feet per second per second
49    pub fn from_feet_per_second_per_second(feet_per_second_per_second: f64) -> Acceleration {
50        Acceleration::from_metres_per_second_per_second(
51            feet_per_second_per_second / length::METER_FEET_FACTOR,
52        )
53    }
54
55    /// Convert this Acceleration to a value in meters per second per second
56    pub fn as_meters_per_second_per_second(&self) -> f64 {
57        self.meters_per_second_per_second
58    }
59
60    /// Convert this Acceleration to a value in metres per second per second
61    pub fn as_metres_per_second_per_second(&self) -> f64 {
62        self.as_meters_per_second_per_second()
63    }
64
65    /// Convert this Acceleration to a value in feet per second per second
66    pub fn as_feet_per_second_per_second(&self) -> f64 {
67        self.meters_per_second_per_second * length::METER_FEET_FACTOR
68    }
69}
70
71impl Measurement for Acceleration {
72    fn as_base_units(&self) -> f64 {
73        self.meters_per_second_per_second
74    }
75
76    fn from_base_units(units: f64) -> Self {
77        Self::from_meters_per_second_per_second(units)
78    }
79
80    fn get_base_units_name(&self) -> &'static str {
81        "m/s\u{00B2}"
82    }
83}
84
85#[cfg(feature = "from_str")]
86impl FromStr for Acceleration {
87    type Err = std::num::ParseFloatError;
88
89    /// Create a new Acceleration from a string
90    /// Plain numbers in string are considered to be meters per second
91    fn from_str(val: &str) -> Result<Self, Self::Err> {
92        if val.is_empty() {
93            return Ok(Acceleration::from_metres_per_second_per_second(0.0));
94        }
95
96        let re = Regex::new(r"(?i)\s*([0-9.]*)\s?([ftmps -1]{1,6})\s*$").unwrap();
97        if let Some(caps) = re.captures(val) {
98            let float_val = caps.get(1).unwrap().as_str();
99            return Ok(
100                match caps.get(2).unwrap().as_str().to_lowercase().as_str() {
101                    "m/s" | "m s-1" => {
102                        Acceleration::from_meters_per_second_per_second(float_val.parse::<f64>()?)
103                    }
104                    "ft/s" | "fps" | "ft s-1" => {
105                        Acceleration::from_feet_per_second_per_second(float_val.parse::<f64>()?)
106                    }
107                    _ => Acceleration::from_meters_per_second_per_second(val.parse::<f64>()?),
108                },
109            );
110        }
111
112        Ok(Acceleration::from_meters_per_second_per_second(
113            val.parse::<f64>()?,
114        ))
115    }
116}
117
118implement_measurement! { Acceleration }
119
120#[cfg(test)]
121mod test {
122
123    use super::*;
124    use speed::Speed;
125    use test_utils::assert_almost_eq;
126
127    // Metric
128    #[test]
129    fn speed_over_time() {
130        let s1 = Speed::from_meters_per_second(10.0);
131        let t1 = ::time::Duration::new(5, 0);
132        let i1 = s1 / t1;
133        let r1 = i1.as_meters_per_second_per_second();
134        assert_almost_eq(r1, 2.0);
135    }
136
137    // Traits
138    #[test]
139    fn add() {
140        let a = Acceleration::from_meters_per_second_per_second(2.0);
141        let b = Acceleration::from_meters_per_second_per_second(4.0);
142        let c = a + b;
143        let d = b + a;
144        assert_almost_eq(c.as_meters_per_second_per_second(), 6.0);
145        assert_eq!(c, d);
146    }
147
148    #[test]
149    fn sub() {
150        let a = Acceleration::from_meters_per_second_per_second(2.0);
151        let b = Acceleration::from_meters_per_second_per_second(4.0);
152        let c = a - b;
153        assert_almost_eq(c.as_meters_per_second_per_second(), -2.0);
154    }
155
156    #[test]
157    fn mul() {
158        let a = Acceleration::from_meters_per_second_per_second(3.0);
159        let b = a * 2.0;
160        let c = 2.0 * a;
161        assert_almost_eq(b.as_meters_per_second_per_second(), 6.0);
162        assert_eq!(b, c);
163    }
164
165    #[test]
166    fn div() {
167        let a = Acceleration::from_meters_per_second_per_second(2.0);
168        let b = Acceleration::from_meters_per_second_per_second(4.0);
169        let c = a / b;
170        let d = a / 2.0;
171        assert_almost_eq(c, 0.5);
172        assert_almost_eq(d.as_meters_per_second_per_second(), 1.0);
173    }
174
175    #[test]
176    fn eq() {
177        let a = Acceleration::from_meters_per_second_per_second(2.0);
178        let b = Acceleration::from_meters_per_second_per_second(2.0);
179        assert_eq!(a == b, true);
180    }
181
182    #[test]
183    fn neq() {
184        let a = Acceleration::from_meters_per_second_per_second(2.0);
185        let b = Acceleration::from_meters_per_second_per_second(4.0);
186        assert_eq!(a == b, false);
187    }
188
189    #[test]
190    fn cmp() {
191        let a = Acceleration::from_meters_per_second_per_second(2.0);
192        let b = Acceleration::from_meters_per_second_per_second(4.0);
193        assert_eq!(a < b, true);
194        assert_eq!(a <= b, true);
195        assert_eq!(a > b, false);
196        assert_eq!(a >= b, false);
197    }
198
199    #[test]
200    #[cfg(feature = "from_str")]
201    fn meters_per_second_str() {
202        let t = Acceleration::from_str(" 12.0m/s");
203        assert!(t.is_ok());
204        let o = t.unwrap().as_meters_per_second_per_second();
205        assert_almost_eq(12.0, o);
206    }
207
208    #[test]
209    #[cfg(feature = "from_str")]
210    fn meters_per_second_minus_str() {
211        let t = Acceleration::from_str("12.0 m s-1");
212        assert!(t.is_ok());
213        let o = t.unwrap().as_meters_per_second_per_second();
214        assert_almost_eq(12.0, o);
215    }
216
217    #[test]
218    #[cfg(feature = "from_str")]
219    fn feet_per_second_str() {
220        let t = Acceleration::from_str(" 12.0ft/s");
221        assert!(t.is_ok());
222        let o = t.unwrap().as_feet_per_second_per_second();
223        assert_almost_eq(12.0, o);
224    }
225
226    #[test]
227    #[cfg(feature = "from_str")]
228    fn feet_per_second_fps_str() {
229        let t = Acceleration::from_str(" 12.0fps");
230        assert!(t.is_ok());
231        let o = t.unwrap().as_feet_per_second_per_second();
232        assert_almost_eq(12.0, o);
233    }
234
235    #[test]
236    #[cfg(feature = "from_str")]
237    fn feet_per_second_minus_str() {
238        let t = Acceleration::from_str("12.0 ft s-1");
239        assert!(t.is_ok());
240        let o = t.unwrap().as_feet_per_second_per_second();
241        assert_almost_eq(12.0, o);
242    }
243
244    #[test]
245    #[cfg(feature = "from_str")]
246    fn number_str() {
247        let t = Acceleration::from_str("100.5");
248        assert!(t.is_ok());
249
250        let o = t.unwrap().as_meters_per_second_per_second();
251        assert_almost_eq(o, 100.5);
252    }
253
254    #[test]
255    #[cfg(feature = "from_str")]
256    fn invalid_str() {
257        let t = Acceleration::from_str("abcd");
258        assert!(t.is_err());
259    }
260}