#![forbid(unsafe_code)]
#![warn(missing_docs)]
pub mod astronomy;
mod checker;
mod date;
mod error;
mod jpholiday;
mod model;
mod registry;
pub use checker::OriginalHolidayChecker;
pub use date::{Date, days_in_month, is_leap_year};
pub use error::DateError;
pub use jpholiday::JPHoliday;
pub use model::Holiday;
use crate::checker::{Checker, compute_holidays};
use crate::registry::HolidayCheckerRegistry;
use std::sync::{Mutex, MutexGuard, OnceLock, PoisonError};
fn registry() -> &'static Mutex<HolidayCheckerRegistry> {
static INSTANCE: OnceLock<Mutex<HolidayCheckerRegistry>> = OnceLock::new();
INSTANCE.get_or_init(|| Mutex::new(HolidayCheckerRegistry::new()))
}
fn locked() -> MutexGuard<'static, HolidayCheckerRegistry> {
registry().lock().unwrap_or_else(PoisonError::into_inner)
}
fn snapshot() -> Vec<Checker> {
locked().snapshot()
}
pub fn holidays(date: Date) -> Vec<Holiday> {
compute_holidays(&snapshot(), date)
}
pub fn is_holiday(date: Date) -> bool {
!holidays(date).is_empty()
}
pub fn is_holiday_name(date: Date) -> Option<String> {
holidays(date).into_iter().next().map(|h| h.name)
}
pub fn year_holidays(year: i32) -> Vec<(Date, String)> {
let checkers = snapshot();
let mut out = Vec::new();
let mut date = Date::new(year, 1, 1).expect("January 1st is always a valid date");
while date.year() == year {
for holiday in compute_holidays(&checkers, date) {
out.push(holiday.into_tuple());
}
date = date.succ();
}
out
}
pub fn month_holidays(year: i32, month: u32) -> Vec<(Date, String)> {
let checkers = snapshot();
let mut out = Vec::new();
let mut date = match Date::new(year, month, 1) {
Ok(d) => d,
Err(_) => return out,
};
while date.month() == month {
for holiday in compute_holidays(&checkers, date) {
out.push(holiday.into_tuple());
}
date = date.succ();
}
out
}
pub fn between(start: Date, end: Date) -> Vec<(Date, String)> {
let checkers = snapshot();
let mut out = Vec::new();
let mut current = start;
while current <= end {
for holiday in compute_holidays(&checkers, current) {
out.push(holiday.into_tuple());
}
current = current.succ();
}
out
}
pub fn register<C: OriginalHolidayChecker + 'static>(checker: C) {
locked().register(checker);
}
pub fn unregister<C: OriginalHolidayChecker + 'static>() {
locked().unregister::<C>();
}