mod calendar;
pub mod error;
mod matcher;
mod utility;
mod recurrences;
pub extern crate time;
use core::any::Any;
use std::collections::{HashMap, hash_map::Keys, hash_set::Iter};
use std::fmt::{self, Display};
use serde::{Serialize, Deserialize};
use time::{Duration, Month, Weekday, OffsetDateTime};
use crate::error::Error;
use crate::matcher::EventRecurrences;
use crate::recurrences::Recurrences;
#[typetag::serde(tag = "type")]
pub trait Recurrent: std::fmt::Debug {
fn periodicity(&self) -> &Periodicity;
fn frequency(&self) -> u16;
fn update_frequency(&mut self, frequency: u16) -> u16;
fn current_date(&self) -> &OffsetDateTime;
fn update_current_date(&mut self, new_date: OffsetDateTime) -> OffsetDateTime;
fn next_date(&mut self) -> Result<OffsetDateTime, Error>;
fn next_date_from(&mut self, from_date: &OffsetDateTime) -> Result<OffsetDateTime, Error>;
fn as_any(&mut self) -> &mut dyn Any;
}
#[derive (Debug, Deserialize, Serialize)]
pub struct DailyEvent {
current_date: OffsetDateTime,
periodicity: Periodicity,
frequency: u16,
}
#[typetag::serde]
impl Recurrent for DailyEvent {
fn current_date(&self) -> &OffsetDateTime {
&self.current_date
}
fn frequency(&self) -> u16 {
self.frequency
}
fn next_date(&mut self) -> Result<OffsetDateTime, Error> {
self.current_date = self.current_date.checked_add(Duration::days(i64::from(self.frequency))).ok_or(Error::DateOverflow)?;
Ok(self.current_date)
}
fn next_date_from(&mut self, from_date: &OffsetDateTime) -> Result<OffsetDateTime, Error> {
if self.current_date.date() == from_date.date() {
self.next_date()
} else {
self.current_date = from_date.replace_time(self.current_date.time()); Ok(self.current_date)
}
}
fn periodicity(&self) -> &Periodicity {
&self.periodicity
}
fn update_current_date(&mut self, new_date: OffsetDateTime) -> OffsetDateTime {
let previous_date = self.current_date.to_owned();
self.current_date = new_date;
previous_date
}
fn update_frequency(&mut self, frequency: u16) -> u16 {
let previous_frequency = self.frequency;
self.frequency = frequency;
previous_frequency
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
impl Iterator for DailyEvent {
type Item = OffsetDateTime;
fn next(&mut self) -> Option<Self::Item> {
self.next_date().ok()
}
}
impl DailyEvent {
pub fn new(current_date: OffsetDateTime) -> DailyEvent {
DailyEvent {
current_date,
periodicity: Periodicity::Daily,
frequency: 1,
}
}
}
impl From<WeeklyEvent> for DailyEvent {
fn from(weekly_event: WeeklyEvent) -> Self {
let date = weekly_event.current_date().to_owned();
let frequency = weekly_event.frequency;
let mut daily_event = DailyEvent::new(date);
daily_event.update_frequency(frequency);
daily_event
}
}
impl From<MonthlyEvent> for DailyEvent {
fn from(monthly_event: MonthlyEvent) -> Self {
let date = monthly_event.current_date().to_owned();
let frequency = monthly_event.frequency;
let mut daily_event = DailyEvent::new(date);
daily_event.update_frequency(frequency);
daily_event
}
}
impl From<YearlyEvent> for DailyEvent {
fn from(yearly_event: YearlyEvent) -> Self {
let date = yearly_event.current_date().to_owned();
let frequency = yearly_event.frequency;
let mut daily_event = DailyEvent::new(date);
daily_event.update_frequency(frequency);
daily_event
}
}
#[derive (Debug, Deserialize, Serialize)]
pub struct WeeklyEvent {
current_date: OffsetDateTime,
periodicity: Periodicity,
frequency: u16,
recurrences: Recurrences,
}
#[typetag::serde]
impl Recurrent for WeeklyEvent {
fn current_date(&self) -> &OffsetDateTime {
&self.current_date
}
fn frequency(&self) -> u16 {
self.frequency
}
fn next_date(&mut self) -> Result<OffsetDateTime, Error> {
if utility::next_day(&self.current_date)? == utility::first_date_of_next_week(&self.current_date)? {
let second_week = self.current_date.checked_add(Duration::weeks(i64::from(self.frequency))).ok_or(Error::DateOverflow)?;
let second_week_date = utility::first_date_of_week(&second_week)?;
self.next_date_from(&second_week_date)
} else {
let next_day = utility::next_day(&self.current_date)?.to_owned();
self.next_date_from(&next_day)
}
}
fn next_date_from(&mut self, from_date: &OffsetDateTime) -> Result<OffsetDateTime, Error> {
if self.recurrences.weekdays().count() == 0 {
return Err(Error::NoRecurrencesDefined);
};
let second_week = from_date.checked_add(Duration::weeks(i64::from(self.frequency))).ok_or(Error::DateOverflow)?;
let second_week_date = utility::first_date_of_week(&second_week)?;
let recurrences = EventRecurrences::Single(&self.recurrences);
let mut new_date = matcher::check_the_from_and_frequenced_periods(matcher::check_week, *from_date, second_week_date, &recurrences)?.ok_or(Error::NoMatchingRecurrences)?;
new_date = new_date.replace_time(self.current_date.time());
self.current_date = new_date;
Ok(self.current_date)
}
fn periodicity(&self) -> &Periodicity {
&self.periodicity
}
fn update_current_date(&mut self, new_date: OffsetDateTime) -> OffsetDateTime {
let previous_date = self.current_date.to_owned();
self.current_date = new_date;
previous_date
}
fn update_frequency(&mut self, frequency: u16) -> u16 {
let previous_frequency = self.frequency;
self.frequency = frequency;
previous_frequency
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
impl Iterator for WeeklyEvent {
type Item = OffsetDateTime;
fn next(&mut self) -> Option<Self::Item> {
self.next_date().ok()
}
}
impl WeeklyEvent {
pub fn insert_weekday(&mut self, weekday: Weekday) -> bool {
self.recurrences.insert_weekday(weekday)
}
pub fn new(current_date: OffsetDateTime) -> WeeklyEvent {
WeeklyEvent {
current_date,
periodicity: Periodicity::Weekly,
frequency: 1,
recurrences: Recurrences::new(),
}
}
pub fn remove_weekday(&mut self, weekday: &Weekday) -> bool {
self.recurrences.remove_weekday(weekday)
}
pub fn weekdays(&self) -> Iter<Weekday> {
self.recurrences.weekdays()
}
}
impl From<DailyEvent> for WeeklyEvent {
fn from(daily_event: DailyEvent) -> Self {
let date = daily_event.current_date().to_owned();
let frequency = daily_event.frequency;
let mut weekly_event = WeeklyEvent::new(date);
weekly_event.update_frequency(frequency);
weekly_event
}
}
impl From<MonthlyEvent> for WeeklyEvent {
fn from(monthly_event: MonthlyEvent) -> Self {
let date = monthly_event.current_date().to_owned();
let frequency = monthly_event.frequency;
let weekdays = monthly_event.weekdays().cloned();
let mut weekly_event = WeeklyEvent::new(date);
weekly_event.update_frequency(frequency);
for weekday in weekdays {
weekly_event.insert_weekday(weekday);
};
weekly_event
}
}
impl From<YearlyEvent> for WeeklyEvent {
fn from(yearly_event: YearlyEvent) -> Self {
let date = yearly_event.current_date().to_owned();
let frequency = yearly_event.frequency;
let mut weekly_event = WeeklyEvent::new(date);
weekly_event.update_frequency(frequency);
weekly_event
}
}
#[derive (Debug, Deserialize, Serialize)]
pub struct MonthlyEvent {
current_date: OffsetDateTime,
periodicity: Periodicity,
frequency: u16,
recurrences: Recurrences,
}
#[typetag::serde]
impl Recurrent for MonthlyEvent {
fn current_date(&self) -> &OffsetDateTime {
&self.current_date
}
fn frequency(&self) -> u16 {
self.frequency
}
fn next_date(&mut self) -> Result<OffsetDateTime, Error> {
if utility::next_day(&self.current_date)? == utility::first_date_of_next_month(&self.current_date)? {
let second_month = utility::first_date_of_month(&self.current_date)?;
let second_month_date = utility::months_later(&second_month, self.frequency)?;
self.next_date_from(&second_month_date)
} else {
let next_day = utility::next_day(&self.current_date)?.to_owned();
self.next_date_from(&next_day)
}
}
fn next_date_from(&mut self, from_date: &OffsetDateTime) -> Result<OffsetDateTime, Error> {
if self.recurrences.weekdays().count() == 0 && self.recurrences.monthly_days_ordinals().count() == 0 && self.recurrences.monthly_weekdays_ordinals().count() == 0 {
return Err(Error::NoRecurrencesDefined);
};
let second_month = utility::first_date_of_month(from_date)?;
let second_month_date = utility::months_later(&second_month, self.frequency)?;
let recurrences = EventRecurrences::Single(&self.recurrences);
let mut new_date = matcher::check_the_from_and_frequenced_periods(matcher::check_month, *from_date, second_month_date, &recurrences)?.ok_or(Error::NoMatchingRecurrences)?;
new_date = new_date.replace_time(self.current_date.time());
self.current_date = new_date;
Ok(self.current_date)
}
fn periodicity(&self) -> &Periodicity {
&self.periodicity
}
fn update_current_date(&mut self, new_date: OffsetDateTime) -> OffsetDateTime {
let previous_date = self.current_date.to_owned();
self.current_date = new_date;
previous_date
}
fn update_frequency(&mut self, frequency: u16) -> u16 {
let previous_frequency = self.frequency;
self.frequency = frequency;
previous_frequency
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
impl Iterator for MonthlyEvent {
type Item = OffsetDateTime;
fn next(&mut self) -> Option<Self::Item> {
self.next_date().ok()
}
}
impl MonthlyEvent {
pub fn insert_monthly_day_ordinal(&mut self, day_ordinal: MonthlyDayOrdinal) -> bool {
self.recurrences.insert_monthly_day_ordinal(day_ordinal)
}
pub fn insert_monthly_weekday_ordinal(&mut self, monthly_weekday_ordinal: MonthlyWeekdayOrdinal) -> bool {
self.recurrences.insert_monthly_weekday_ordinal(monthly_weekday_ordinal)
}
pub fn insert_weekday(&mut self, weekday: Weekday) -> bool {
self.recurrences.insert_weekday(weekday)
}
pub fn monthly_days_ordinals(&self) -> Iter<MonthlyDayOrdinal> {
self.recurrences.monthly_days_ordinals()
}
pub fn monthly_weekdays_ordinals(&self) -> Iter<MonthlyWeekdayOrdinal> {
self.recurrences.monthly_weekdays_ordinals()
}
pub fn new(current_date: OffsetDateTime) -> MonthlyEvent {
MonthlyEvent {
current_date,
periodicity: Periodicity::Monthly,
frequency: 1,
recurrences: Recurrences::new(),
}
}
pub fn remove_monthly_day_ordinal(&mut self, day_ordinal: &MonthlyDayOrdinal) -> bool {
self.recurrences.remove_monthly_day_ordinal(day_ordinal)
}
pub fn remove_monthly_weekday_ordinal(&mut self, monthly_weekday_ordinal: &MonthlyWeekdayOrdinal) -> bool {
self.recurrences.remove_monthly_weekday_ordinal(&monthly_weekday_ordinal)
}
pub fn remove_weekday(&mut self, weekday: &Weekday) -> bool {
self.recurrences.remove_weekday(weekday)
}
pub fn weekdays(&self) -> Iter<Weekday> {
self.recurrences.weekdays()
}
}
impl From<DailyEvent> for MonthlyEvent {
fn from(daily_event: DailyEvent) -> Self {
let date = daily_event.current_date().to_owned();
let frequency = daily_event.frequency;
let mut monthly_event = MonthlyEvent::new(date);
monthly_event.update_frequency(frequency);
monthly_event
}
}
impl From<WeeklyEvent> for MonthlyEvent {
fn from(weekly_event: WeeklyEvent) -> Self {
let date = weekly_event.current_date().to_owned();
let frequency = weekly_event.frequency;
let weekdays = weekly_event.weekdays().cloned();
let mut monthly_event = MonthlyEvent::new(date);
monthly_event.update_frequency(frequency);
for weekday in weekdays {
monthly_event.insert_weekday(weekday);
};
monthly_event
}
}
impl From<YearlyEvent> for MonthlyEvent {
fn from(yearly_event: YearlyEvent) -> Self {
let date = yearly_event.current_date().to_owned();
let frequency = yearly_event.frequency;
let mut monthly_event = MonthlyEvent::new(date);
monthly_event.update_frequency(frequency);
monthly_event
}
}
#[derive (Debug, Deserialize, Serialize)]
pub struct YearlyEvent {
current_date: OffsetDateTime,
periodicity: Periodicity,
frequency: u16,
recurrences_by_month: HashMap<Month, Recurrences>,
}
#[typetag::serde]
impl Recurrent for YearlyEvent {
fn current_date(&self) -> &OffsetDateTime {
&self.current_date
}
fn frequency(&self) -> u16 {
self.frequency
}
fn next_date(&mut self) -> Result<OffsetDateTime, Error> {
if utility::next_day(&self.current_date)? == utility::first_date_of_next_year(&self.current_date)? {
let second_year_date = self.current_date.replace_day(1)?.replace_month(Month::January)?.replace_year(self.current_date.year() + self.frequency() as i32)?;
self.next_date_from(&second_year_date)
} else {
let next_day = utility::next_day(&self.current_date)?.to_owned();
self.next_date_from(&next_day)
}
}
fn next_date_from(&mut self, from_date: &OffsetDateTime) -> Result<OffsetDateTime, Error> {
if self.recurrences_by_month.is_empty() ||
self.recurrences_by_month.iter().all(|(_month, recurrences)| recurrences.weekdays().count() == 0 && recurrences.monthly_days_ordinals().count() == 0
&& recurrences.monthly_weekdays_ordinals().count() ==0) {
return Err(Error::NoRecurrencesDefined);
}
let second_year_date = from_date.replace_day(1)?.replace_month(Month::January)?.replace_year(from_date.year() + self.frequency() as i32)?;
let recurrences = EventRecurrences::Multiple(&self.recurrences_by_month);
let mut new_date = matcher::check_the_from_and_frequenced_periods(matcher::check_year, *from_date, second_year_date, &recurrences)?.ok_or(Error::NoMatchingRecurrences)?;
new_date = new_date.replace_time(self.current_date.time());
self.current_date = new_date;
Ok(self.current_date)
}
fn periodicity(&self) -> &Periodicity {
&self.periodicity
}
fn update_current_date(&mut self, new_date: OffsetDateTime) -> OffsetDateTime {
let previous_date = self.current_date.to_owned();
self.current_date = new_date;
previous_date
}
fn update_frequency(&mut self, frequency: u16) -> u16 {
let previous_frequency = self.frequency;
self.frequency = frequency;
previous_frequency
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
impl Iterator for YearlyEvent {
type Item = OffsetDateTime;
fn next(&mut self) -> Option<Self::Item> {
self.next_date().ok()
}
}
impl YearlyEvent {
pub fn insert_monthly_day_ordinal(&mut self, monthly_day_ordinal: MonthlyDayOrdinal, month: Month) -> bool {
self.recurrences_by_month.entry(month).or_insert_with(|| {Recurrences::new()}).insert_monthly_day_ordinal(monthly_day_ordinal)
}
pub fn insert_monthly_weekday_ordinal(&mut self, monthly_weekday_ordinal: MonthlyWeekdayOrdinal, month: Month) -> bool {
self.recurrences_by_month.entry(month).or_insert_with(|| {Recurrences::new()}).insert_monthly_weekday_ordinal(monthly_weekday_ordinal)
}
pub fn insert_weekday(&mut self, weekday: Weekday, month: Month) -> bool {
self.recurrences_by_month.entry(month).or_insert_with(|| {Recurrences::new()}).insert_weekday(weekday)
}
pub fn monthly_days_ordinals(&self, month: Month) -> Result<Iter<MonthlyDayOrdinal>, Error> {
Ok(self.recurrences_by_month.get(&month).ok_or(Error::NotFound)?.monthly_days_ordinals())
}
pub fn monthly_weekdays_ordinals(&self, month: Month) -> Result<Iter<MonthlyWeekdayOrdinal>, Error> {
Ok(self.recurrences_by_month.get(&month).ok_or(Error::NotFound)?.monthly_weekdays_ordinals())
}
pub fn months(&self) -> Keys<'_, Month, Recurrences> {
self.recurrences_by_month.keys()
}
pub fn new(current_date: OffsetDateTime) -> YearlyEvent {
YearlyEvent {
current_date,
periodicity: Periodicity::Yearly,
frequency: 1,
recurrences_by_month: HashMap::new(),
}
}
pub fn remove_monthly_day_ordinal(&mut self, monthly_day_ordinal: &MonthlyDayOrdinal, month: Month) -> bool {
self.remove_recurrence(monthly_day_ordinal, month, Recurrences::remove_monthly_day_ordinal)
}
pub fn remove_monthly_weekday_ordinal(&mut self, monthly_weekday_ordinal: &MonthlyWeekdayOrdinal, month: Month) -> bool {
self.remove_recurrence(monthly_weekday_ordinal, month, Recurrences::remove_monthly_weekday_ordinal)
}
fn remove_recurrence<T>(&mut self, recurrence: T, month: Month, remove: fn(&mut Recurrences, T) -> bool) -> bool {
let recurrences_ = self.recurrences_by_month.get_mut(&month);
if recurrences_.is_some() {
let recurrences = recurrences_.unwrap();
remove(recurrences, recurrence)
} else {
false
}
}
pub fn remove_weekday(&mut self, weekday: &Weekday, month: Month) -> bool {
self.remove_recurrence(weekday, month, Recurrences::remove_weekday)
}
pub fn weekdays(&self, month: Month) -> Result<Iter<Weekday>, Error> {
Ok(self.recurrences_by_month.get(&month).ok_or(Error::NotFound)?.weekdays())
}
}
impl From<DailyEvent> for YearlyEvent {
fn from(daily_event: DailyEvent) -> Self {
let date = daily_event.current_date().to_owned();
let frequency = daily_event.frequency;
let mut yearly_event = YearlyEvent::new(date);
yearly_event.update_frequency(frequency);
yearly_event
}
}
impl From<WeeklyEvent> for YearlyEvent {
fn from(weekly_event: WeeklyEvent) -> Self {
let date = weekly_event.current_date().to_owned();
let frequency = weekly_event.frequency;
let mut yearly_event = YearlyEvent::new(date);
yearly_event.update_frequency(frequency);
yearly_event
}
}
impl From<MonthlyEvent> for YearlyEvent {
fn from(monthly_event: MonthlyEvent) -> Self {
let date = monthly_event.current_date().to_owned();
let frequency = monthly_event.frequency;
let mut yearly_event = YearlyEvent::new(date);
yearly_event.update_frequency(frequency);
yearly_event
}
}
#[derive (Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum Ordinal {
First,
Second,
Third,
Fourth,
Fifth,
Last,
}
impl Display for Ordinal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Ordinal::First => "First",
Ordinal::Second => "Second",
Ordinal::Third => "Third",
Ordinal::Fourth => "Fourth",
Ordinal::Fifth => "Fifth",
Ordinal::Last => "Last",
})
}
}
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum Periodicity {
Daily,
Weekly,
Monthly,
Yearly,
}
impl Display for Periodicity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Periodicity::Daily => "Daily",
Periodicity::Weekly => "Weekly",
Periodicity::Monthly => "Monthly",
Periodicity::Yearly => "Yearly",
})
}
}
pub type MonthlyDayOrdinal = u8;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct MonthlyWeekdayOrdinal {
pub ordinal: Ordinal,
pub weekday: Weekday,
}
impl Display for MonthlyWeekdayOrdinal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.ordinal, self.weekday)
}
}
impl MonthlyWeekdayOrdinal {
pub fn new(ordinal: Ordinal, weekday: Weekday) -> MonthlyWeekdayOrdinal {
MonthlyWeekdayOrdinal {
ordinal,
weekday,
}
}
}