///|
/// Create an inclusive date-window constraint.
pub fn DeadlineConstraint::within(
start~ : Date,
end~ : Date,
) -> Result[DeadlineConstraint, ConstraintError] {
if start > end {
Err(ConstraintInvalidRange)
} else {
Ok(Within(start, end))
}
}
///|
/// Require the calculated date to be a business day.
pub fn DeadlineConstraint::must_be_business_day() -> DeadlineConstraint {
MustBeBusinessDay
}
///|
/// Reject a result that crosses a calendar year from its start.
pub fn DeadlineConstraint::not_crossing_year() -> DeadlineConstraint {
NotCrossingYear
}
///|
/// Create a deadline with no constraints.
pub fn ConstrainedDeadline::new(
start_date~ : Date,
rule~ : DateRule,
start_rule~ : StartDateRule,
calendar~ : Calendar,
extension~ : ExtensionPolicy,
) -> ConstrainedDeadline {
{ start_date, rule, start_rule, calendar, extension, constraints: [] }
}
///|
/// Add one validated constraint.
pub fn ConstrainedDeadline::add_constraint(
self : ConstrainedDeadline,
constraint : DeadlineConstraint,
) -> Result[ConstrainedDeadline, ConstraintError] {
let constraints = self.constraints.copy()
constraints.push(constraint)
Ok({ ..self, constraints, })
}
///|
/// Calculate and enforce every constraint in insertion order.
pub fn ConstrainedDeadline::calculate(
self : ConstrainedDeadline,
) -> Result[DeadlineResult, ConstraintError] {
let deadline = Deadline::new(
start_date=self.start_date,
rule=self.rule,
start_rule=self.start_rule,
calendar=self.calendar,
extension=self.extension,
)
let result = match deadline.calculate() {
Ok(value) => value
Err(error) => return Err(ConstraintDeadlineFailure(error))
}
for constraint in self.constraints {
match constraint {
Within(start, end) =>
if result.adjusted_date() < start || result.adjusted_date() > end {
return Err(ConstraintViolation("within"))
}
MustBeBusinessDay =>
if !self.calendar.is_business_day(result.adjusted_date()) {
return Err(ConstraintViolation("must-be-business-day"))
}
NotCrossingYear =>
if result.start_date().year != result.adjusted_date().year {
return Err(ConstraintViolation("not-crossing-year"))
}
}
}
Ok(result)
}