jana_sessions_webpage/session_iter/src/session.rs
2025-02-20 10:55:18 +01:00

197 lines
4.4 KiB
Rust

pub mod iter;
pub mod rule;
use crate::day::Day;
use crate::session::rule::{SessionRule, WeekdayOfMonth};
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 {
Regular(RegularSession),
Extra(ExtraSession),
}
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 {
pub rule: SessionRule,
pub note: Note,
#[serde(with = "serde_json_any_key::any_key_map")]
pub except: BTreeMap<Day, Except>,
}
impl From<SessionRule> for RegularSession {
fn from(rule: SessionRule) -> Self {
Self {
rule,
note: None,
except: Default::default(),
}
}
}
impl RegularSession {
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))
}
}
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 {
pub day: Day,
pub note: Note,
}
impl From<Day> for ExtraSession {
fn from(day: Day) -> Self {
Self { day, note: None }
}
}
impl_from!(NaiveDate for ExtraSession by Day);
impl_opt_noted!(ExtraSession);
impl_with_note!(ExtraSession);
impl Dated for ExtraSession {
fn day(&self) -> Day {
self.day
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum Except {
Alternation(Alternation),
Cancellation(Cancellation),
}
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 {
pub note: Note,
///the date when the alternation should show up in the calendar, or the original date
pub new_day: Option<Day>,
}
impl From<Day> for Alternation {
fn from(day: Day) -> Self {
Self {
new_day: Some(day),
..Default::default()
}
}
}
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 {
pub note: Note,
}
impl Cancellation {
pub fn new() -> Self {
Self::default()
}
}
impl_opt_noted!(Cancellation);
impl_with_note!(Cancellation);
pub trait Dated {
/// The day when this should show up in a calendar
fn day(&self) -> Day;
}
pub trait OptNoted {
fn note(&self) -> Option<&str>;
}
pub trait WithNote {
fn with_note(self, note: &str) -> Self;
}