use crate::interval::AllenRelation;
use crate::pattern::*;
use std::collections::HashMap;
pub struct PatternBuilder<L, V> {
name: String,
stages: Vec<Stage<L, V>>,
temporal: Vec<TemporalConstraint>,
negations: Vec<Negation<L, V>>,
metadata: HashMap<String, String>,
deadline_ticks: Option<u64>,
unordered_groups: Vec<Vec<usize>>,
private: bool,
}
impl<L: Clone, V: Clone> PatternBuilder<L, V> {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
stages: Vec::new(),
temporal: Vec::new(),
negations: Vec::new(),
metadata: HashMap::new(),
deadline_ticks: None,
unordered_groups: Vec::new(),
private: false,
}
}
pub fn stage(
mut self,
anchor: impl Into<String>,
build: impl FnOnce(StageBuilder<L, V>) -> StageBuilder<L, V>,
) -> Self {
let builder = StageBuilder::new(anchor.into());
let builder = build(builder);
self.stages.push(builder.build());
self
}
pub fn temporal(
mut self,
left: impl Into<String>,
relation: AllenRelation,
right: impl Into<String>,
) -> Self {
self.temporal.push(TemporalConstraint {
left: Var::new(left),
relation,
right: Var::new(right),
gap: None,
});
self
}
pub fn temporal_with_gap(
mut self,
left: impl Into<String>,
relation: AllenRelation,
right: impl Into<String>,
gap: MetricGap,
) -> Self {
self.temporal.push(TemporalConstraint {
left: Var::new(left),
relation,
right: Var::new(right),
gap: Some(gap),
});
self
}
pub fn unless_between(
mut self,
start: impl Into<String>,
end: impl Into<String>,
build: impl FnOnce(NegationBuilder<L, V>) -> NegationBuilder<L, V>,
) -> Self {
let builder = NegationBuilder::new(start.into(), Some(end.into()));
let builder = build(builder);
self.negations.push(builder.build());
self
}
pub fn unless_after(
mut self,
start: impl Into<String>,
build: impl FnOnce(NegationBuilder<L, V>) -> NegationBuilder<L, V>,
) -> Self {
let builder = NegationBuilder::new(start.into(), None);
let builder = build(builder);
self.negations.push(builder.build());
self
}
pub fn deadline(mut self, ticks: u64) -> Self {
self.deadline_ticks = Some(ticks);
self
}
pub fn private(mut self) -> Self {
self.private = true;
self
}
pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metadata.insert(key.into(), value.into());
self
}
pub fn unless_global(
mut self,
build: impl FnOnce(NegationBuilder<L, V>) -> NegationBuilder<L, V>,
) -> Self {
let builder = NegationBuilder::new(String::new(), None);
let builder = build(builder);
let mut neg = builder.build();
neg.is_global = true;
self.negations.push(neg);
self
}
pub fn unordered_group(
mut self,
build: impl FnOnce(UnorderedGroupBuilder<L, V>) -> UnorderedGroupBuilder<L, V>,
) -> Self {
let start_idx = self.stages.len();
let group_builder = UnorderedGroupBuilder::new();
let group_builder = build(group_builder);
let stages = group_builder.stages;
let count = stages.len();
debug_assert!(count >= 2, "unordered group should have at least 2 stages");
self.stages.extend(stages);
if count > 0 {
let end_idx = start_idx + count - 1;
debug_assert!(
end_idx < 64,
"unordered group stage indices must be < 64 (matched_stages is u64)"
);
let indices: Vec<usize> = (start_idx..start_idx + count).collect();
self.unordered_groups.push(indices);
}
self
}
pub fn build(mut self) -> Pattern<L, V> {
let first_anchor = self.stages.first().map(|s| s.anchor.0.clone());
let last_anchor = self.stages.last().map(|s| s.anchor.0.clone());
for neg in &mut self.negations {
if neg.is_global {
if let Some(ref first) = first_anchor {
neg.between_start = Var::new(first.clone());
neg.between_end = match &last_anchor {
Some(last) if last != first => Some(Var::new(last.clone())),
_ => None, };
}
neg.is_global = false; }
}
Pattern {
name: self.name,
stages: self.stages,
temporal: self.temporal,
negations: self.negations,
group: None,
metadata: self.metadata,
deadline_ticks: self.deadline_ticks,
repeat_range: None,
unordered_groups: self.unordered_groups,
private: self.private,
}
}
}
pub struct StageBuilder<L, V> {
anchor: String,
clauses: Vec<Clause<L, V>>,
}
impl<L: Clone, V: Clone> StageBuilder<L, V> {
fn new(anchor: String) -> Self {
Self {
anchor,
clauses: Vec::new(),
}
}
pub fn edge(mut self, source: impl Into<String>, label: L, value: V) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Literal(value),
negated: false,
});
self
}
pub fn edge_bind(
mut self,
source: impl Into<String>,
label: L,
bind_to: impl Into<String>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Bind(Var::new(bind_to)),
negated: false,
});
self
}
pub fn edge_constrained(
mut self,
source: impl Into<String>,
label: L,
constraint: crate::datasource::ValueConstraint<V>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Constraint(constraint),
negated: false,
});
self
}
pub fn edge_eq_var(
mut self,
source: impl Into<String>,
label: L,
var_name: impl Into<String>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Constraint(crate::datasource::ValueConstraint::EqVar(var_name.into())),
negated: false,
});
self
}
pub fn edge_lt_var(
mut self,
source: impl Into<String>,
label: L,
var_name: impl Into<String>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Constraint(crate::datasource::ValueConstraint::LtVar(var_name.into())),
negated: false,
});
self
}
pub fn edge_gt_var(
mut self,
source: impl Into<String>,
label: L,
var_name: impl Into<String>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Constraint(crate::datasource::ValueConstraint::GtVar(var_name.into())),
negated: false,
});
self
}
pub fn edge_lte_var(
mut self,
source: impl Into<String>,
label: L,
var_name: impl Into<String>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Constraint(crate::datasource::ValueConstraint::LteVar(var_name.into())),
negated: false,
});
self
}
pub fn edge_gte_var(
mut self,
source: impl Into<String>,
label: L,
var_name: impl Into<String>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Constraint(crate::datasource::ValueConstraint::GteVar(var_name.into())),
negated: false,
});
self
}
pub fn not_edge(mut self, source: impl Into<String>, label: L, value: V) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Literal(value),
negated: true,
});
self
}
fn build(self) -> Stage<L, V> {
Stage {
anchor: Var::new(self.anchor),
clauses: self.clauses,
}
}
}
pub struct NegationBuilder<L, V> {
between_start: String,
between_end: Option<String>,
clauses: Vec<Clause<L, V>>,
}
impl<L: Clone, V: Clone> NegationBuilder<L, V> {
fn new(start: String, end: Option<String>) -> Self {
Self {
between_start: start,
between_end: end,
clauses: Vec::new(),
}
}
pub fn edge(mut self, source: impl Into<String>, label: L, value: V) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Literal(value),
negated: false,
});
self
}
pub fn edge_bind(
mut self,
source: impl Into<String>,
label: L,
bind_to: impl Into<String>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Bind(Var::new(bind_to)),
negated: false,
});
self
}
pub fn edge_constrained(
mut self,
source: impl Into<String>,
label: L,
constraint: crate::datasource::ValueConstraint<V>,
) -> Self {
self.clauses.push(Clause {
source: Var::new(source),
label,
target: Target::Constraint(constraint),
negated: false,
});
self
}
fn build(self) -> Negation<L, V> {
Negation {
between_start: Var::new(self.between_start),
between_end: self.between_end.map(Var::new),
clauses: self.clauses,
is_global: false,
}
}
}
pub struct UnorderedGroupBuilder<L, V> {
stages: Vec<Stage<L, V>>,
}
impl<L: Clone, V: Clone> UnorderedGroupBuilder<L, V> {
fn new() -> Self {
Self { stages: Vec::new() }
}
pub fn stage(
mut self,
anchor: impl Into<String>,
build: impl FnOnce(StageBuilder<L, V>) -> StageBuilder<L, V>,
) -> Self {
let builder = StageBuilder::new(anchor.into());
let builder = build(builder);
self.stages.push(builder.build());
self
}
}