extern crate chrono;
use std::fmt;
use std::str::FromStr;
use chrono::NaiveDate;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::error::RParifError;
#[derive(Clone, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Index {
date: NaiveDate,
url: Option<String>,
pollutants: Vec<String>,
index: u32,
insee: Option<String>,
}
impl Index {
pub fn new(
date: NaiveDate,
url: Option<String>,
pollutants: Vec<String>,
index: u32,
insee: Option<String>,
) -> Index {
Index {
date,
url,
pollutants,
index,
insee,
}
}
pub fn date(&self) -> NaiveDate {
self.date
}
pub fn map_url(&self) -> Option<String> {
self.url.clone()
}
pub fn pollutants(&self) -> Vec<String> {
self.pollutants.to_vec()
}
pub fn index(&self) -> u32 {
self.index
}
pub fn insee(&self) -> Option<String> {
self.insee.clone()
}
}
impl fmt::Display for Index {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} (city : {:?}) : {:?} = {} (map : {:?})",
self.date, self.insee, self.pollutants, self.index, self.url
)
}
}
pub enum Day {
Yesterday,
Today,
Tomorrow,
}
#[derive(Clone, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Episode {
date: NaiveDate,
detail: Option<String>,
pollutants: Vec<PollutantEpisode>,
}
impl Episode {
pub fn new(date: NaiveDate, detail: Option<String>) -> Episode {
Episode {
date,
detail,
pollutants: vec![],
}
}
pub fn add(&mut self, pollutant: String, kind: Type, level: Level, criteria: Vec<Criteria>) {
self.pollutants.push(PollutantEpisode {
pollutant,
kind,
level,
criteria,
})
}
pub fn date(&self) -> NaiveDate {
self.date
}
pub fn detail(&self) -> Option<String> {
self.detail.clone()
}
pub fn pollutants(&self) -> Vec<PollutantEpisode> {
self.pollutants.to_vec()
}
}
impl fmt::Display for Episode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {:?} (detail : {:?})",
self.date, self.pollutants, self.detail
)
}
}
impl IntoIterator for Episode {
type Item = PollutantEpisode;
type IntoIter = PollutantEpisodeIter;
fn into_iter(self) -> Self::IntoIter {
PollutantEpisodeIter {
episode: self,
i: 0,
}
}
}
pub struct PollutantEpisodeIter {
episode: Episode,
i: usize,
}
impl Iterator for PollutantEpisodeIter {
type Item = PollutantEpisode;
fn next(&mut self) -> Option<Self::Item> {
if self.i < self.episode.pollutants.len() {
let episode: PollutantEpisode = self.episode.pollutants().get(self.i).unwrap().clone();
self.i += 1;
Some(episode)
} else {
None
}
}
}
#[derive(Clone, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PollutantEpisode {
pollutant: String,
kind: Type,
level: Level,
criteria: Vec<Criteria>,
}
impl PollutantEpisode {
pub fn pollutant_name(&self) -> String {
self.pollutant.clone()
}
pub fn kind(&self) -> Type {
self.kind.clone()
}
pub fn level(&self) -> Level {
self.level.clone()
}
pub fn criteria(&self) -> Vec<Criteria> {
self.criteria.to_vec()
}
}
impl fmt::Display for PollutantEpisode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} : {:?} {:?} {:?}",
self.pollutant, self.kind, self.level, self.criteria
)
}
}
#[derive(Clone, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Level {
Info,
Alert,
Normal,
}
impl FromStr for Level {
type Err = RParifError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "info" {
Ok(Level::Info)
} else if s == "alerte" {
Ok(Level::Alert)
} else if s == "normal" {
Ok(Level::Normal)
} else {
Err(RParifError::UnkownEnumValue(s.to_string()))
}
}
}
#[derive(Clone, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Type {
Forecast,
Observed,
}
impl FromStr for Type {
type Err = RParifError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "prevu" {
Ok(Type::Forecast)
} else if s == "constate" {
Ok(Type::Observed)
} else {
Err(RParifError::UnkownEnumValue(s.to_string()))
}
}
}
#[derive(Clone, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Criteria {
Area,
Population,
}
impl FromStr for Criteria {
type Err = RParifError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "km" {
Ok(Criteria::Area)
} else if s == "pop" {
Ok(Criteria::Population)
} else {
Err(RParifError::UnkownEnumValue(s.to_string()))
}
}
}
#[cfg(test)]
mod test {
use crate::objects::{Criteria, Episode, Level, Type};
use super::chrono::{Datelike, NaiveDate, Utc};
#[test]
fn test_episode_iterator() {
let today = Utc::today();
let mut episode = Episode::new(
NaiveDate::from_ymd_opt(today.year(), today.month(), today.day()).unwrap(),
None,
);
episode.add(
"o3".to_string(),
Type::Observed,
Level::Info,
vec![Criteria::Area, Criteria::Population],
);
episode.add(
"so2".to_string(),
Type::Observed,
Level::Alert,
vec![Criteria::Population],
);
episode.add(
"no2".to_string(),
Type::Observed,
Level::Normal,
vec![Criteria::Area],
);
let mut i: usize = 0;
for pollution_episode in episode.clone() {
assert_eq!(
pollution_episode,
episode.pollutants().get(i).unwrap().clone()
);
i += 1;
}
}
}