#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize)]
#[repr(u8)]
#[non_exhaustive]
pub enum WmoCode {
ClearSky = 0,
MainlyClear = 1,
PartlyCloudy = 2,
Overcast = 3,
Fog = 45,
DepositingRimeFog = 48,
DrizzleLight = 51,
DrizzleModerate = 53,
DrizzleDense = 55,
FreezingDrizzleLight = 56,
FreezingDrizzleDense = 57,
RainSlight = 61,
RainModerate = 63,
RainHeavy = 65,
FreezingRainLight = 66,
FreezingRainHeavy = 67,
SnowFallSlight = 71,
SnowFallModerate = 73,
SnowFallHeavy = 75,
SnowGrains = 77,
RainShowersSlight = 80,
RainShowersModerate = 81,
RainShowersViolent = 82,
SnowShowersSlight = 85,
SnowShowersHeavy = 86,
ThunderstormSlightOrModerate = 95,
ThunderstormWithSlightHail = 96,
ThunderstormWithHeavyHail = 99,
}
impl WmoCode {
pub fn from_code(code: u8) -> Option<Self> {
Some(match code {
0 => Self::ClearSky,
1 => Self::MainlyClear,
2 => Self::PartlyCloudy,
3 => Self::Overcast,
45 => Self::Fog,
48 => Self::DepositingRimeFog,
51 => Self::DrizzleLight,
53 => Self::DrizzleModerate,
55 => Self::DrizzleDense,
56 => Self::FreezingDrizzleLight,
57 => Self::FreezingDrizzleDense,
61 => Self::RainSlight,
63 => Self::RainModerate,
65 => Self::RainHeavy,
66 => Self::FreezingRainLight,
67 => Self::FreezingRainHeavy,
71 => Self::SnowFallSlight,
73 => Self::SnowFallModerate,
75 => Self::SnowFallHeavy,
77 => Self::SnowGrains,
80 => Self::RainShowersSlight,
81 => Self::RainShowersModerate,
82 => Self::RainShowersViolent,
85 => Self::SnowShowersSlight,
86 => Self::SnowShowersHeavy,
95 => Self::ThunderstormSlightOrModerate,
96 => Self::ThunderstormWithSlightHail,
99 => Self::ThunderstormWithHeavyHail,
_ => return None,
})
}
pub fn description(self) -> &'static str {
match self {
Self::ClearSky => "clear sky",
Self::MainlyClear => "mainly clear",
Self::PartlyCloudy => "partly cloudy",
Self::Overcast => "overcast",
Self::Fog => "fog",
Self::DepositingRimeFog => "depositing rime fog",
Self::DrizzleLight => "light drizzle",
Self::DrizzleModerate => "moderate drizzle",
Self::DrizzleDense => "dense drizzle",
Self::FreezingDrizzleLight => "light freezing drizzle",
Self::FreezingDrizzleDense => "dense freezing drizzle",
Self::RainSlight => "slight rain",
Self::RainModerate => "moderate rain",
Self::RainHeavy => "heavy rain",
Self::FreezingRainLight => "light freezing rain",
Self::FreezingRainHeavy => "heavy freezing rain",
Self::SnowFallSlight => "slight snow fall",
Self::SnowFallModerate => "moderate snow fall",
Self::SnowFallHeavy => "heavy snow fall",
Self::SnowGrains => "snow grains",
Self::RainShowersSlight => "slight rain showers",
Self::RainShowersModerate => "moderate rain showers",
Self::RainShowersViolent => "violent rain showers",
Self::SnowShowersSlight => "slight snow showers",
Self::SnowShowersHeavy => "heavy snow showers",
Self::ThunderstormSlightOrModerate => "slight or moderate thunderstorm",
Self::ThunderstormWithSlightHail => "thunderstorm with slight hail",
Self::ThunderstormWithHeavyHail => "thunderstorm with heavy hail",
}
}
pub fn is_precipitating(self) -> bool {
matches!(
self,
Self::DrizzleLight
| Self::DrizzleModerate
| Self::DrizzleDense
| Self::FreezingDrizzleLight
| Self::FreezingDrizzleDense
| Self::RainSlight
| Self::RainModerate
| Self::RainHeavy
| Self::FreezingRainLight
| Self::FreezingRainHeavy
| Self::SnowFallSlight
| Self::SnowFallModerate
| Self::SnowFallHeavy
| Self::SnowGrains
| Self::RainShowersSlight
| Self::RainShowersModerate
| Self::RainShowersViolent
| Self::SnowShowersSlight
| Self::SnowShowersHeavy
| Self::ThunderstormSlightOrModerate
| Self::ThunderstormWithSlightHail
| Self::ThunderstormWithHeavyHail
)
}
pub fn is_thunderstorm(self) -> bool {
matches!(
self,
Self::ThunderstormSlightOrModerate
| Self::ThunderstormWithSlightHail
| Self::ThunderstormWithHeavyHail
)
}
pub fn severity(self) -> Severity {
match self {
Self::ClearSky | Self::MainlyClear | Self::PartlyCloudy => Severity::Clear,
Self::DrizzleLight
| Self::FreezingDrizzleLight
| Self::RainSlight
| Self::FreezingRainLight
| Self::SnowFallSlight
| Self::RainShowersSlight
| Self::SnowShowersSlight => Severity::Light,
Self::Overcast
| Self::Fog
| Self::DepositingRimeFog
| Self::DrizzleModerate
| Self::RainModerate
| Self::SnowFallModerate
| Self::SnowGrains
| Self::RainShowersModerate
| Self::ThunderstormSlightOrModerate => Severity::Moderate,
Self::DrizzleDense
| Self::FreezingDrizzleDense
| Self::RainHeavy
| Self::FreezingRainHeavy
| Self::SnowFallHeavy
| Self::RainShowersViolent
| Self::SnowShowersHeavy => Severity::Heavy,
Self::ThunderstormWithSlightHail | Self::ThunderstormWithHeavyHail => Severity::Severe,
}
}
}
#[cfg(test)]
mod tests {
use super::{Severity, WmoCode};
#[test]
fn all_documented_open_meteo_codes_are_supported() {
for (code, expected) in [
(0, WmoCode::ClearSky),
(1, WmoCode::MainlyClear),
(2, WmoCode::PartlyCloudy),
(3, WmoCode::Overcast),
(45, WmoCode::Fog),
(48, WmoCode::DepositingRimeFog),
(51, WmoCode::DrizzleLight),
(53, WmoCode::DrizzleModerate),
(55, WmoCode::DrizzleDense),
(56, WmoCode::FreezingDrizzleLight),
(57, WmoCode::FreezingDrizzleDense),
(61, WmoCode::RainSlight),
(63, WmoCode::RainModerate),
(65, WmoCode::RainHeavy),
(66, WmoCode::FreezingRainLight),
(67, WmoCode::FreezingRainHeavy),
(71, WmoCode::SnowFallSlight),
(73, WmoCode::SnowFallModerate),
(75, WmoCode::SnowFallHeavy),
(77, WmoCode::SnowGrains),
(80, WmoCode::RainShowersSlight),
(81, WmoCode::RainShowersModerate),
(82, WmoCode::RainShowersViolent),
(85, WmoCode::SnowShowersSlight),
(86, WmoCode::SnowShowersHeavy),
(95, WmoCode::ThunderstormSlightOrModerate),
(96, WmoCode::ThunderstormWithSlightHail),
(99, WmoCode::ThunderstormWithHeavyHail),
] {
assert_eq!(WmoCode::from_code(code), Some(expected));
assert!(!expected.description().is_empty());
}
assert_eq!(WmoCode::from_code(4), None);
}
#[test]
fn weather_code_helpers_classify_precipitation_and_storms() {
assert!(!WmoCode::ClearSky.is_precipitating());
assert!(WmoCode::FreezingRainLight.is_precipitating());
assert!(WmoCode::RainShowersViolent.is_precipitating());
assert!(WmoCode::ThunderstormWithSlightHail.is_thunderstorm());
assert_eq!(
WmoCode::ThunderstormWithHeavyHail.severity(),
Severity::Severe
);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize)]
#[non_exhaustive]
pub enum Severity {
Clear,
Light,
Moderate,
Heavy,
Severe,
}