use crate::shared::shared;
use crate::time::calendar::{Calendar, CalendarImpl};
use crate::time::date::Date;
use crate::time::weekday::Weekday;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum JointCalendarRule {
JoinHolidays,
JoinBusinessDays,
}
pub struct JointCalendar;
impl JointCalendar {
pub fn new(calendars: Vec<Calendar>, rule: JointCalendarRule) -> Calendar {
assert!(!calendars.is_empty(), "at least one calendar required");
Calendar::from_impl(shared(Impl { rule, calendars }))
}
pub fn of_two(c1: Calendar, c2: Calendar, rule: JointCalendarRule) -> Calendar {
Self::new(vec![c1, c2], rule)
}
}
struct Impl {
rule: JointCalendarRule,
calendars: Vec<Calendar>,
}
impl CalendarImpl for Impl {
fn name(&self) -> String {
let prefix = match self.rule {
JointCalendarRule::JoinHolidays => "JoinHolidays(",
JointCalendarRule::JoinBusinessDays => "JoinBusinessDays(",
};
let mut out = String::from(prefix);
for (i, c) in self.calendars.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
out.push_str(&c.name());
}
out.push(')');
out
}
fn is_weekend(&self, w: Weekday) -> bool {
match self.rule {
JointCalendarRule::JoinHolidays => self.calendars.iter().any(|c| c.is_weekend(w)),
JointCalendarRule::JoinBusinessDays => self.calendars.iter().all(|c| c.is_weekend(w)),
}
}
fn is_business_day(&self, date: Date) -> bool {
match self.rule {
JointCalendarRule::JoinHolidays => {
self.calendars.iter().all(|c| c.is_business_day(date))
}
JointCalendarRule::JoinBusinessDays => {
self.calendars.iter().any(|c| c.is_business_day(date))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::time::calendars::target::Target;
use crate::time::calendars::weekendsonly::WeekendsOnly;
use crate::time::date::Month;
#[test]
fn join_holidays_is_holiday_if_any_is() {
let joint = JointCalendar::of_two(
Target::new(),
WeekendsOnly::new(),
JointCalendarRule::JoinHolidays,
);
let christmas = Date::new(25, Month::December, 2018); assert!(joint.is_holiday(christmas));
}
#[test]
fn join_business_days_is_business_if_any_is() {
let joint = JointCalendar::of_two(
Target::new(),
WeekendsOnly::new(),
JointCalendarRule::JoinBusinessDays,
);
let christmas = Date::new(25, Month::December, 2018);
assert!(joint.is_business_day(christmas));
}
#[test]
fn name_lists_members() {
let joint = JointCalendar::of_two(
Target::new(),
WeekendsOnly::new(),
JointCalendarRule::JoinHolidays,
);
assert_eq!(joint.name(), "JoinHolidays(TARGET, weekends only)");
}
}