///|
/// Start assembling a calendar with explicit identity and weekend policy.
pub fn CalendarBuilder::new(
name~ : String,
version~ : String,
weekend~ : WeekendPolicy,
) -> CalendarBuilder {
{
name,
version,
region: "",
source: CalendarSource::new(name="", url=""),
valid_from: None,
valid_to: None,
weekend,
holidays: [],
extra_workdays: [],
}
}
///|
/// Set a jurisdiction or organization label.
pub fn CalendarBuilder::region(
self : CalendarBuilder,
region : String,
) -> CalendarBuilder {
{ ..self, region, }
}
///|
/// Set the source metadata for the assembled calendar.
pub fn CalendarBuilder::source(
self : CalendarBuilder,
source : CalendarSource,
) -> CalendarBuilder {
{ ..self, source, }
}
///|
/// Set the inclusive validity interval.
pub fn CalendarBuilder::valid_during(
self : CalendarBuilder,
start~ : Date,
end~ : Date,
) -> CalendarBuilder {
{ ..self, valid_from: Some(start), valid_to: Some(end) }
}
///|
/// Add a holiday. Duplicate dates are removed during build.
pub fn CalendarBuilder::holiday(
self : CalendarBuilder,
date : Date,
) -> CalendarBuilder {
let holidays = self.holidays.copy()
holidays.push(date)
{ ..self, holidays, }
}
///|
/// Add an exceptional workday, which has priority over closure dates.
pub fn CalendarBuilder::extra_workday(
self : CalendarBuilder,
date : Date,
) -> CalendarBuilder {
let extra_workdays = self.extra_workdays.copy()
extra_workdays.push(date)
{ ..self, extra_workdays, }
}
///|
/// Validate and build a calendar.
pub fn CalendarBuilder::build(
self : CalendarBuilder,
) -> Result[Calendar, CalendarValidationError] {
if self.name.length() == 0 {
return Err(CalendarMissingName)
}
if self.version.length() == 0 {
return Err(CalendarMissingVersion)
}
let valid_from = match self.valid_from {
Some(value) => value
None => return build_unversioned(self)
}
let valid_to = match self.valid_to {
Some(value) => value
None => return Err(CalendarInvalidRange)
}
if valid_from > valid_to {
return Err(CalendarInvalidRange)
}
let version = match
CalendarVersion::new(
name=self.name,
region=self.region,
version=self.version,
source=self.source,
valid_from~,
valid_to~,
) {
Ok(value) => value
Err(_) => return Err(CalendarInvalidRange)
}
let calendar = Calendar::new(
name=version.name(),
version=version.version(),
weekend=self.weekend,
holidays=normalize_dates(self.holidays),
extra_workdays=normalize_dates(self.extra_workdays),
)
Ok(calendar.with_version(version))
}
///|
fn build_unversioned(
builder : CalendarBuilder,
) -> Result[Calendar, CalendarValidationError] {
if builder.valid_to != None {
return Err(CalendarInvalidRange)
}
Ok(
Calendar::new(
name=builder.name,
version=builder.version,
weekend=builder.weekend,
holidays=normalize_dates(builder.holidays),
extra_workdays=normalize_dates(builder.extra_workdays),
),
)
}
///|
/// Validate a calendar assembled by any API.
pub fn Calendar::validate(
self : Calendar,
) -> Result[Unit, CalendarValidationError] {
if self.name.length() == 0 {
return Err(CalendarMissingName)
}
if self.version.length() == 0 {
return Err(CalendarMissingVersion)
}
if self.versioned && self.valid_from > self.valid_to {
return Err(CalendarInvalidRange)
}
for holiday in self.holidays {
if self.extra_workdays.contains(holiday) {
continue
}
}
Ok(())
}