diff --git a/src/lib.rs b/src/lib.rs index 7cb2af2..f770fa1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,102 +1,10 @@ -use crate::session_date_calculator::{Day, NthWeekday}; -use chrono::{NaiveDate, Weekday}; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use crate::session_date_calculator::Day; +use chrono::Weekday; +pub mod session; pub mod session_date_calculator; pub mod webpage; -#[derive(Debug, Clone)] -pub struct DatedSession { - pub day: Day, - pub session: Session, - pub applying_exception: Option, -} - -impl Noted for DatedSession { - fn note(&self) -> Option<&String> { - match &self.applying_exception { - Some(e) => e.note(), - None => self.session.note(), - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -pub enum Session { - Regular { - rule: NthWeekday, - note: Option, - except: HashMap, - }, - Extra { - date: NaiveDate, - note: Option, - }, -} - -impl Session { - pub fn into_dated(self, day: Day) -> Result { - if !self.is_applicable_to(&day) { - return Err(self); - } - - let dated_session = DatedSession { - applying_exception: match self { - Session::Regular { ref except, .. } => except.get(&day.date).cloned(), - _ => None, - }, - session: self, - day, - }; - Ok(dated_session) - } - - pub fn is_applicable_to(&self, day: &Day) -> bool { - match *self { - Session::Regular { rule, .. } => rule.matches(day), - Session::Extra { date, .. } => day.date == date, - } - } -} - -impl Noted for Session { - fn note(&self) -> Option<&String> { - match self { - Session::Regular { note, .. } => note, - Session::Extra { note, .. } => note, - } - .as_ref() - } -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] -pub enum Exception { - Cancel { - note: Option, - }, - Alter { - #[serde(default)] - date: Option, - #[serde(default)] - note: Option, - }, -} - -impl Noted for Exception { - fn note(&self) -> Option<&String> { - match self { - Exception::Cancel { note, .. } => note, - Exception::Alter { note, .. } => note, - } - .as_ref() - } -} - -pub trait Noted { - fn note(&self) -> Option<&String>; -} - pub fn localize_day(day: &Day) -> String { format!( "{}, {}", diff --git a/src/session.rs b/src/session.rs new file mode 100644 index 0000000..1891913 --- /dev/null +++ b/src/session.rs @@ -0,0 +1,208 @@ +use crate::session_date_calculator::{Day, NthWeekday}; +use chrono::NaiveDate; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct DatedSession { + pub day: Day, + pub session: Session, + pub applying_exception: Option, +} + +impl Noted for DatedSession { + fn get_note(&self) -> Option<&String> { + match &self.applying_exception { + Some(e) => e.get_note(), + None => self.session.get_note(), + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub enum Session { + Regular(RegularSession), + Extra(ExtraSession), +} + +impl From for Session { + fn from(value: RegularSession) -> Self { + Self::Regular(value) + } +} + +impl From for Session { + fn from(value: ExtraSession) -> Self { + Self::Extra(value) + } +} + +impl Session { + pub fn into_dated(self, day: Day) -> Result { + if !self.is_applicable_to(&day) { + return Err(self); + } + + let dated_session = DatedSession { + applying_exception: match self { + Session::Regular(RegularSession { ref except, .. }) => except.get(&day.date).cloned(), + _ => None, + }, + session: self, + day, + }; + Ok(dated_session) + } + + pub fn is_applicable_to(&self, day: &Day) -> bool { + match *self { + Session::Regular(RegularSession { rule, .. }) => rule.matches(day), + Session::Extra(ExtraSession { date, .. }) => day.date == date, + } + } +} + +impl Noted for Session { + fn get_note(&self) -> Option<&String> { + match self { + Session::Regular(session) => session.get_note(), + Session::Extra(session) => session.get_note(), + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct RegularSession { + pub rule: NthWeekday, + pub note: Option, + pub except: HashMap, +} + +impl From for RegularSession { + fn from(rule: NthWeekday) -> Self { + Self { + rule, + note: None, + except: Default::default(), + } + } +} + +impl RegularSession { + pub fn with_exception(mut self, date: D, exception: E) -> Self + where + D: Into, + E: Into, + { + self.except.insert(date.into(), exception.into()); + self + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct ExtraSession { + pub date: NaiveDate, + pub note: Option, +} + +impl From for ExtraSession { + fn from(date: NaiveDate) -> Self { + Self { date, note: None } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub enum Exception { + Cancel(CancelException), + Alter(AlterException), +} + +impl From for Exception { + fn from(value: CancelException) -> Self { + Self::Cancel(value) + } +} + +impl From for Exception { + fn from(value: AlterException) -> Self { + Self::Alter(value) + } +} + +impl Noted for Exception { + fn get_note(&self) -> Option<&String> { + match self { + Exception::Cancel(exception) => exception.get_note(), + Exception::Alter(exception) => exception.get_note(), + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, Serialize, Deserialize)] +#[serde(default)] +pub struct CancelException { + pub note: Option, +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, Serialize, Deserialize)] +#[serde(default)] +pub struct AlterException { + pub date: Option, + pub note: Option, +} + +impl From for AlterException { + fn from(value: NaiveDate) -> Self { + Self { + date: Some(value), + ..Self::default() + } + } +} + +pub trait Noted { + fn get_note(&self) -> Option<&String>; +} + +macro_rules! impl_noted { + ($ty: ident) => { + impl Noted for $ty { + fn get_note(&self) -> Option<&String> { + self.note.as_ref() + } + } + }; +} + +impl_noted!(RegularSession); +impl_noted!(ExtraSession); +impl_noted!(AlterException); +impl_noted!(CancelException); + +pub trait WithNote { + fn with_note(self, note: S) -> Self + where + S: ToString; +} + +macro_rules! impl_with_node { + ($ty: ident) => { + impl WithNote for $ty { + fn with_note(self, note: S) -> Self + where + S: ToString, + { + #[allow(clippy::needless_update)] + Self { + note: Some(note.to_string()), + ..self + } + } + } + }; +} + +impl_with_node!(AlterException); +impl_with_node!(CancelException); +impl_with_node!(ExtraSession); +impl_with_node!(RegularSession); diff --git a/src/session_date_calculator.rs b/src/session_date_calculator.rs index 3d1e396..0ed3a5b 100644 --- a/src/session_date_calculator.rs +++ b/src/session_date_calculator.rs @@ -96,7 +96,7 @@ impl Iterator for DayIter { } } -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct Day { pub date: NaiveDate, pub weekday: Weekday,