use chumsky::prelude::*;
use crate::{parsers::temperature, traits::Parsable, Data};
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SeaCondition {
pub temperature: Data<i32>,
pub condition: Data<SeaConditionInner>,
}
impl Parsable for SeaCondition {
fn parser<'src>() -> impl Parser<'src, &'src str, Self, extra::Err<crate::MetarError<'src>>> {
group((
just("W"),
Data::parser_inline(2, temperature()),
just("/"),
Data::parser_inline(2, SeaConditionInner::parser()),
))
.map(|(_, temperature, _, condition)| SeaCondition {
temperature,
condition,
})
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SeaConditionInner {
State(Data<SeaState>),
WaveHeight(Data<u32>),
}
impl Parsable for SeaConditionInner {
fn parser<'src>() -> impl Parser<'src, &'src str, Self, extra::Err<crate::MetarError<'src>>> {
choice((
just("S")
.then(Data::parser_inline(1, SeaState::parser()))
.map(|(_, s)| SeaConditionInner::State(s)),
just("H")
.then(Data::parser_inline(
2,
text::digits(10)
.at_least(1)
.at_most(3)
.to_slice()
.map(|d: &str| d.parse::<u32>().unwrap()),
))
.map(|(_, h)| SeaConditionInner::WaveHeight(h)),
))
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(missing_docs)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SeaState {
CalmGlassy,
CalmRippled,
Smooth,
Slight,
Moderate,
Rough,
VeryRough,
High,
VeryHigh,
Phenomenal,
}
impl Parsable for SeaState {
fn parser<'src>() -> impl Parser<'src, &'src str, Self, extra::Err<crate::MetarError<'src>>> {
choice((
just("0").map(|_| SeaState::CalmGlassy),
just("1").map(|_| SeaState::CalmRippled),
just("2").map(|_| SeaState::Smooth),
just("3").map(|_| SeaState::Slight),
just("4").map(|_| SeaState::Moderate),
just("5").map(|_| SeaState::Rough),
just("6").map(|_| SeaState::VeryRough),
just("7").map(|_| SeaState::High),
just("8").map(|_| SeaState::VeryHigh),
just("9").map(|_| SeaState::Phenomenal),
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sea_condition() {
assert_eq!(
SeaCondition::parse("W15/S2").unwrap(),
SeaCondition {
temperature: Data::Known(15),
condition: Data::Known(SeaConditionInner::State(Data::Known(SeaState::Smooth))),
}
);
assert_eq!(
SeaCondition::parse("W15/H123").unwrap(),
SeaCondition {
temperature: Data::Known(15),
condition: Data::Known(SeaConditionInner::WaveHeight(Data::Known(123))),
}
);
}
}