use std::ops::{Bound, RangeBounds};
use crate::history::HistoryId;
use crate::sequence::destination::SequenceDestination;
use crate::sequence::{Separator, Sequence};
use crate::symbol::Symbol;
pub struct SequenceRuleBuilder<D> {
lhs: Option<Symbol>,
range: Option<(u32, Option<u32>)>,
separator: Separator,
history: Option<HistoryId>,
default_history: Option<HistoryId>,
destination: D,
}
impl<D> SequenceRuleBuilder<D>
where
D: SequenceDestination,
{
pub fn new(destination: D) -> Self {
SequenceRuleBuilder {
lhs: None,
range: None,
history: None,
default_history: None,
separator: Separator::Null,
destination: destination,
}
}
pub fn default_history(self, default_history: HistoryId) -> SequenceRuleBuilder<D> {
SequenceRuleBuilder {
lhs: self.lhs,
range: self.range,
history: self.history,
default_history: Some(default_history),
separator: self.separator,
destination: self.destination,
}
}
pub fn sequence(mut self, lhs: Symbol) -> Self {
self.lhs = Some(lhs);
self.separator = Separator::Null;
self
}
pub fn separator(mut self, sep: Separator) -> Self {
self.separator = sep;
self
}
pub fn intersperse(self, sym: Symbol) -> Self {
self.separator(Separator::Proper(sym))
}
pub fn history(mut self, history: HistoryId) -> Self {
self.history = Some(history);
self
}
pub fn inclusive(mut self, start: u32, end: Option<u32>) -> Self {
self.range = Some((start, end));
self
}
pub fn rhs(mut self, rhs: Symbol) -> Self {
let history = self.history.take().or(self.default_history);
self.rhs_with_history(rhs, history)
}
pub fn range(self, range: impl RangeBounds<u32>) -> Self {
let to_option = |bound: Bound<u32>, diff| match bound {
Bound::Included(included) => Some(included),
Bound::Excluded(excluded) => Some((excluded as i64 + diff) as u32),
Bound::Unbounded => None,
};
self.inclusive(
to_option(range.start_bound().cloned(), 1).unwrap_or(0),
to_option(range.end_bound().cloned(), -1),
)
}
pub fn rhs_with_range(self, rhs: Symbol, range: impl RangeBounds<u32>) -> Self {
self.range(range).rhs(rhs)
}
pub fn rhs_with_history(mut self, rhs: Symbol, history_id: Option<HistoryId>) -> Self {
let (start, end) = self.range.take().expect("expected inclusive(n, m)");
self.destination.add_sequence(Sequence {
lhs: self.lhs.unwrap(),
rhs,
start,
end,
separator: self.separator,
history_id,
});
self
}
}