2025-02-17 20:18:41 +01:00
|
|
|
pub mod iter;
|
|
|
|
|
pub mod rule;
|
|
|
|
|
|
|
|
|
|
use crate::day::Day;
|
2025-02-17 22:40:49 +01:00
|
|
|
use crate::session::rule::{SessionRule, WeekdayOfMonth};
|
2025-02-17 20:18:41 +01:00
|
|
|
use chrono::NaiveDate;
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
|
|
|
|
|
type Note = Option<String>;
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_opt_noted {
|
|
|
|
|
($ty: ident) => {
|
|
|
|
|
impl OptNoted for $ty {
|
|
|
|
|
fn note(&self) -> Option<&str> {
|
|
|
|
|
self.note.as_ref().map(String::as_str)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
($ty: ident with $($variant: ident),+) => {
|
|
|
|
|
impl OptNoted for $ty {
|
|
|
|
|
fn note(&self) -> Option<&str> {
|
|
|
|
|
match self {
|
|
|
|
|
$(Self::$variant(opt_noted) => opt_noted.note(),)+
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_with_note {
|
|
|
|
|
($ty: ident) => {
|
|
|
|
|
impl WithNote for $ty {
|
|
|
|
|
fn with_note(self, note: &str) -> Self {
|
|
|
|
|
#[allow(clippy::needless_update)]
|
|
|
|
|
Self {
|
|
|
|
|
note: Some(note.to_owned()),
|
|
|
|
|
..self
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_from {
|
|
|
|
|
($what: ident for $ty: ident by $intermediate: ident) => {
|
|
|
|
|
impl From<$what> for $ty {
|
|
|
|
|
fn from(value: $what) -> Self {
|
|
|
|
|
Self::from($intermediate::from(value))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
($what: ident for $ty: ident as $variant: ident) => {
|
|
|
|
|
impl From<$what> for $ty {
|
|
|
|
|
fn from(value: $what) -> Self {
|
|
|
|
|
Self::$variant(value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
($what: ident for $ty: ident) => {
|
|
|
|
|
impl_from!($what for $ty as $what);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
|
|
|
|
pub enum Session {
|
2025-02-20 10:55:18 +01:00
|
|
|
Regular(RegularSession),
|
|
|
|
|
Extra(ExtraSession),
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_from!(RegularSession for Session as Regular);
|
|
|
|
|
impl_from!(ExtraSession for Session as Extra);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
|
|
|
|
pub struct RegularSession {
|
2025-02-20 10:55:18 +01:00
|
|
|
pub rule: SessionRule,
|
|
|
|
|
pub note: Note,
|
|
|
|
|
#[serde(with = "serde_json_any_key::any_key_map")]
|
|
|
|
|
pub except: BTreeMap<Day, Except>,
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<SessionRule> for RegularSession {
|
2025-02-20 10:55:18 +01:00
|
|
|
fn from(rule: SessionRule) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
rule,
|
|
|
|
|
note: None,
|
|
|
|
|
except: Default::default(),
|
|
|
|
|
}
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RegularSession {
|
2025-02-20 10:55:18 +01:00
|
|
|
pub fn except<D, E>(mut self, day: D, except: E) -> Self
|
|
|
|
|
where
|
|
|
|
|
D: Into<Day>,
|
|
|
|
|
E: Into<Except>,
|
|
|
|
|
{
|
|
|
|
|
self.except.insert(day.into(), except.into());
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///gets the next session day, where no except applies. Can possibly return the `current_date`.
|
|
|
|
|
pub fn next_regular_session_day<D>(&self, current_date: D) -> Option<Day>
|
|
|
|
|
where
|
|
|
|
|
D: Into<Day>,
|
|
|
|
|
{
|
|
|
|
|
self
|
|
|
|
|
.rule
|
|
|
|
|
.to_session_day_iter(current_date)
|
|
|
|
|
.find(|day| !self.except.contains_key(day))
|
|
|
|
|
}
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_from!(WeekdayOfMonth for RegularSession by SessionRule);
|
|
|
|
|
impl_opt_noted!(RegularSession);
|
|
|
|
|
impl_with_note!(RegularSession);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
|
|
|
|
pub struct ExtraSession {
|
2025-02-20 10:55:18 +01:00
|
|
|
pub day: Day,
|
|
|
|
|
pub note: Note,
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Day> for ExtraSession {
|
2025-02-20 10:55:18 +01:00
|
|
|
fn from(day: Day) -> Self {
|
|
|
|
|
Self { day, note: None }
|
|
|
|
|
}
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_from!(NaiveDate for ExtraSession by Day);
|
|
|
|
|
impl_opt_noted!(ExtraSession);
|
|
|
|
|
impl_with_note!(ExtraSession);
|
|
|
|
|
|
|
|
|
|
impl Dated for ExtraSession {
|
2025-02-20 10:55:18 +01:00
|
|
|
fn day(&self) -> Day {
|
|
|
|
|
self.day
|
|
|
|
|
}
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
|
|
|
|
pub enum Except {
|
2025-02-20 10:55:18 +01:00
|
|
|
Alternation(Alternation),
|
|
|
|
|
Cancellation(Cancellation),
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_from!(Alternation for Except);
|
|
|
|
|
impl_from!(Cancellation for Except);
|
|
|
|
|
impl_opt_noted!(Except with Alternation, Cancellation);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, Serialize, Deserialize)]
|
|
|
|
|
pub struct Alternation {
|
2025-02-20 10:55:18 +01:00
|
|
|
pub note: Note,
|
|
|
|
|
///the date when the alternation should show up in the calendar, or the original date
|
|
|
|
|
pub new_day: Option<Day>,
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Day> for Alternation {
|
2025-02-20 10:55:18 +01:00
|
|
|
fn from(day: Day) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
new_day: Some(day),
|
|
|
|
|
..Default::default()
|
|
|
|
|
}
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_from!(NaiveDate for Alternation by Day);
|
|
|
|
|
impl_opt_noted!(Alternation);
|
|
|
|
|
impl_with_note!(Alternation);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, Serialize, Deserialize)]
|
|
|
|
|
#[serde(default)]
|
|
|
|
|
pub struct Cancellation {
|
2025-02-20 10:55:18 +01:00
|
|
|
pub note: Note,
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-17 23:30:44 +01:00
|
|
|
impl Cancellation {
|
2025-02-20 10:55:18 +01:00
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self::default()
|
|
|
|
|
}
|
2025-02-17 23:30:44 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-17 20:18:41 +01:00
|
|
|
impl_opt_noted!(Cancellation);
|
|
|
|
|
impl_with_note!(Cancellation);
|
|
|
|
|
|
|
|
|
|
pub trait Dated {
|
2025-02-20 10:55:18 +01:00
|
|
|
/// The day when this should show up in a calendar
|
|
|
|
|
fn day(&self) -> Day;
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub trait OptNoted {
|
2025-02-20 10:55:18 +01:00
|
|
|
fn note(&self) -> Option<&str>;
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub trait WithNote {
|
2025-02-20 10:55:18 +01:00
|
|
|
fn with_note(self, note: &str) -> Self;
|
2025-02-17 20:18:41 +01:00
|
|
|
}
|