use std::str::FromStr;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::constants;
use super::{Measurement, PhysicalQuantity, UnitOfMeasure};
use crate::error::Error;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(C)]
pub enum SpeedUnit {
MetersPerSecond,
Knots,
Mach,
}
impl UnitOfMeasure<f32> for SpeedUnit {
fn quantity() -> PhysicalQuantity {
PhysicalQuantity::Speed
}
fn si() -> Self {
Self::MetersPerSecond
}
fn symbol(&self) -> &'static str {
match self {
Self::MetersPerSecond => "mps",
Self::Knots => "kt",
Self::Mach => "mach",
}
}
fn from_si(value: f32, to: &Self) -> f32 {
match to {
Self::MetersPerSecond => value,
Self::Knots => value * constants::METER_PER_SECONDS_IN_KNOTS,
Self::Mach => unimplemented!(),
}
}
fn to_si(&self, value: &f32) -> f32 {
match self {
Self::MetersPerSecond => *value,
Self::Knots => value / constants::METER_PER_SECONDS_IN_KNOTS,
Self::Mach => unimplemented!(),
}
}
}
pub type Speed = Measurement<f32, SpeedUnit>;
impl Speed {
pub fn mps(value: f32) -> Self {
Measurement {
value,
unit: SpeedUnit::MetersPerSecond,
}
}
pub fn kt(value: f32) -> Self {
Measurement {
value,
unit: SpeedUnit::Knots,
}
}
pub fn mach(value: f32) -> Self {
Measurement {
value,
unit: SpeedUnit::Mach,
}
}
}
impl FromStr for Speed {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
macro_rules! value {
($s:expr, $index:expr) => {
$s.get($index)
.and_then(|s| s.parse::<u16>().ok()) .map(|value| value as f32)
.ok_or(Error::UnexpectedString)
};
}
match s.get(0..1).unwrap_or_default() {
"K" => Ok(Speed::mps(value!(s, 1..5)? / 3.6)), "N" => Ok(Speed::kt(value!(s, 1..5)?)),
"M" => Ok(Speed::mach(value!(s, 1..4)? / 100.0)), _ => Err(Error::UnexpectedString),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_icao_4444_2_str() {
assert_eq!("K0360".parse::<Speed>(), Ok(Speed::mps(100.0)));
assert_eq!("N0485".parse::<Speed>(), Ok(Speed::kt(485.0)));
assert_eq!("M08".parse::<Speed>(), Err(Error::UnexpectedString));
}
}