pub(crate) mod canonical;
pub(crate) mod frame;
pub(crate) mod paving;
use crate::normalize::paving::{EmptyPavingSelector, Paving, Paving4D, UnpackFromBack};
use crate::rules::day::DaySelector;
use crate::rules::time::TimeSelector;
use crate::rules::{RuleOperator, RuleSequence};
use crate::RuleKind;
use self::canonical::{Canonical, CanonicalSelector, MakeCanonical};
use self::paving::SelectorCompression;
pub(crate) fn ruleseq_to_selector(rs: &RuleSequence) -> Option<CanonicalSelector> {
let ds = &rs.day_selector;
let selector = EmptyPavingSelector
.dim_front(MakeCanonical::try_from_iterator(&rs.time_selector.time)?)
.dim_front(MakeCanonical::try_from_iterator(&ds.year)?)
.dim_front(MakeCanonical::try_from_iterator(&ds.monthday)?)
.dim_front(MakeCanonical::try_from_iterator(&ds.week)?)
.dim_front(MakeCanonical::try_from_iterator(&ds.weekday)?);
Some(selector)
}
pub(crate) fn canonical_to_seq(canonical: Canonical) -> impl Iterator<Item = RuleSequence> {
let mut days_covered = Paving4D::default();
let mut canonical_remaining = canonical.clone();
core::iter::from_fn(move || {
let ((kind, comments), mut selector) =
[RuleKind::Open, RuleKind::Unknown, RuleKind::Closed]
.into_iter()
.find_map(|target_kind| {
canonical_remaining.pop_filter(|(kind, comments)| {
*kind == target_kind
&& (target_kind != RuleKind::Closed || !comments.is_empty())
})
})?;
selector.fill_holes({
let canonical = &canonical;
let val = (kind, comments.clone());
move |candidate| canonical.is_val(candidate, &val)
});
let (day_selector, rgs_time) = selector.into_unpack_back();
let operator = {
let no_day_overlap = days_covered.is_val(&day_selector, &false);
if no_day_overlap {
RuleOperator::Normal
} else {
RuleOperator::Additional
}
};
days_covered.set(&day_selector, &true);
let (rgs_weekday, day_selector) = day_selector.into_unpack_front();
let (rgs_week, day_selector) = day_selector.into_unpack_front();
let (rgs_monthday, day_selector) = day_selector.into_unpack_front();
let (rgs_year, EmptyPavingSelector) = day_selector.into_unpack_front();
let day_selector = DaySelector {
year: MakeCanonical::into_selector(rgs_year, true),
monthday: MakeCanonical::into_selector(rgs_monthday, true),
week: MakeCanonical::into_selector(rgs_week, true),
weekday: MakeCanonical::into_selector(rgs_weekday, true),
};
let time_selector = TimeSelector {
time: MakeCanonical::into_selector(rgs_time, false),
};
Some(RuleSequence {
day_selector,
time_selector,
kind,
operator,
comments,
})
})
}