Skip to main content

Patterns & Builders

fabula::pattern -- compiled pattern types. fabula::builder -- ergonomic construction API.

Pattern types

Var

A named position in a pattern traversal. Variables appearing in multiple clauses create joins.

pub struct Var(pub String);
FieldTypeDescription
0StringThe variable name.

Methods

Var::new
pub fn new(name: impl Into<String>) -> Self
ParameterTypeRequiredDefaultDescription
nameimpl Into<String>yes--Variable name.

Returns: Var

Trait implementations

Debug, Clone, PartialEq, Eq, Hash, Display (formats as ?name).


Target<V>

Specifies what an edge's target must match.

pub enum Target<V> {
Bind(Var),
Literal(V),
Constraint(ValueConstraint<V>),
}
VariantDescription
Bind(Var)Bind the target to a variable for traversal or join.
Literal(V)The target must equal this exact value.
Constraint(ValueConstraint<V>)The target must satisfy this constraint.

Trait implementations

Debug, Clone.


Clause<L, V>

A single edge traversal constraint within a stage.

pub struct Clause<L, V> {
pub source: Var,
pub label: L,
pub target: Target<V>,
pub negated: bool,
}
FieldTypeDescription
sourceVarSource node variable. Must be bound by a prior clause or be a scan root.
labelLEdge label to follow.
targetTarget<V>What the target must match.
negatedboolIf true, the edge must NOT exist.

Trait implementations

Debug, Clone.


Stage<L, V>

A group of clauses anchored to a single event/node variable. Stages are the units of incremental matching -- each new edge tests against the next unmatched stage.

pub struct Stage<L, V> {
pub anchor: Var,
pub clauses: Vec<Clause<L, V>>,
}
FieldTypeDescription
anchorVarThe event/node variable this stage is anchored to.
clausesVec<Clause<L, V>>Clauses that constrain this event/node.

Trait implementations

Debug, Clone.


TemporalConstraint

An explicit temporal ordering constraint between two event variables (beyond implicit left-to-right stage ordering).

pub struct TemporalConstraint {
pub left: Var,
pub relation: AllenRelation,
pub right: Var,
pub gap: Option<MetricGap>,
}
FieldTypeDescription
leftVarVariable whose interval should come first.
relationAllenRelationRequired Allen relation (typically Before or Meets).
rightVarVariable whose interval should come second.
gapOption<MetricGap>Optional metric bound (STN-style bounded difference). Set via temporal_with_gap on the builder or gap min..max in the DSL.

Trait implementations

Debug, Clone.


Negation<L, V>

A negation window -- a set of clauses that must NOT all match between two events. All clauses must match for the negation to fire (conjunctive).

pub struct Negation<L, V> {
pub between_start: Var,
pub between_end: Option<Var>,
pub clauses: Vec<Clause<L, V>>,
}
FieldTypeDescription
between_startVarStart of the negation window (must be bound).
between_endOption<Var>End of the negation window. None means open-ended (up to "now").
clausesVec<Clause<L, V>>Clauses that must NOT all match within the window.

Trait implementations

Debug, Clone.


Pattern<L, V>

A compiled sifting pattern -- a named subgraph template with temporal constraints and negation windows.

pub struct Pattern<L, V> {
pub name: String,
pub stages: Vec<Stage<L, V>>,
pub temporal: Vec<TemporalConstraint>,
pub negations: Vec<Negation<L, V>>,
pub group: Option<String>,
pub metadata: HashMap<String, String>,
pub deadline_ticks: Option<u64>,
pub repeat_range: Option<RepeatRange>,
pub unordered_groups: Vec<Vec<usize>>,
pub private: bool,
}
FieldTypeDescription
nameStringPattern name, used in match results and gap analysis.
stagesVec<Stage<L, V>>Ordered event stages. Temporally ordered left-to-right.
temporalVec<TemporalConstraint>Explicit temporal constraints beyond implicit ordering.
negationsVec<Negation<L, V>>Negation windows.
groupOption<String>Mutual-exclusion group. When one pattern in a group completes, the engine kills active PMs for all other patterns in the same group. Set by choice composition.
metadataHashMap<String, String>Arbitrary key-value pairs propagated to Match, SiftEvent, and scored match types. Use for tagging patterns with narrative roles, priorities, or domain-specific attributes.
deadline_ticksOption<u64>If set, active partial matches for this pattern are expired (killed with SiftEvent::Expired) when they have been alive for more than this many ticks without completing. Checked during end_tick().
repeat_rangeOption<RepeatRange>Looping repeat configuration. Set by compose::repeat_range() or DSL * N..M / * N... When present, the engine loops over a segment of stages instead of completing after the last stage. See DSL Reference — Repeat.
unordered_groupsVec<Vec<usize>>Stage groups that can match in any order. Each inner Vec<usize> lists stage indices that form a concurrent group. Set by PatternBuilder::unordered_group() or DSL concurrent { }. See DSL Reference — Concurrent Groups.
privateboolIf true, this pattern's matches and events are suppressed from engine output (evaluate(), drain_completed(), on_edge_added()). The engine still evaluates the pattern internally for composition and exclusive group handling. Default false. Set by PatternBuilder::private() or DSL private pattern.

Methods

all_vars

Returns all variables used in this pattern (across all stages and negations), sorted and deduplicated.

pub fn all_vars(&self) -> Vec<&Var>

unordered_group_for

Returns the unordered group containing the given stage index, if any.

pub fn unordered_group_for(&self, stage_idx: usize) -> Option<&Vec<usize>>

same_unordered_group

Returns true if two stage indices are in the same unordered group.

pub fn same_unordered_group(&self, a: usize, b: usize) -> bool

condition_count

Total number of clauses across all stages in the pattern.

pub fn condition_count(&self) -> usize

map_types

Convert a pattern from one type system to another. Applies label_fn to all labels and value_fn to all values, producing a new pattern with different L2/V2 types. All fields (stages, negations, temporal constraints, unordered groups, metadata, repeat range) are preserved.

pub fn map_types<L2, V2>(
&self,
label_fn: impl Fn(&L) -> L2,
value_fn: impl Fn(&V) -> V2,
) -> Pattern<L2, V2>

Trait implementations

Debug, Clone.


RepeatRange

Configuration for looping repeat patterns (DSL * N..M or * N..). The pattern's stages are laid out as [first_... | last_...]. The last_ segment loops in the engine.

pub struct RepeatRange {
pub stage_start: usize,
pub stage_end: usize,
pub min_reps: usize,
pub max_reps: Option<usize>,
pub shared_vars: HashSet<String>,
}
FieldTypeDescription
stage_startusizeFirst stage index of the looping segment (inclusive).
stage_endusizeLast stage index of the looping segment (exclusive).
min_repsusizeMinimum total occurrences before the first completion. * 3.. means 3.
max_repsOption<usize>Maximum total occurrences. None = unlimited (* N..).
shared_varsHashSet<String>Variables shared across repetitions (not prefixed, persist across loops).

Bindings in repeat-range matches:

  • first_* — variables from the first sub-pattern occurrence (preserved across loops)
  • last_* — variables from the most recent occurrence (overwritten each loop iteration)
  • Shared variables — unprefixed, consistent across all iterations

Trait implementations: Debug, Clone, PartialEq.


Builders

PatternBuilder<L, V>

Ergonomic builder for constructing a Pattern. Requires L: Clone, V: Clone.

let pattern = PatternBuilder::<String, MemValue>::new("my_pattern")
.stage("event1", |s| {
s.edge("event1", "type".into(), MemValue::Str("failure".into()))
.edge_bind("event1", "actor".into(), "character")
})
.stage("event2", |s| {
s.edge("event2", "type".into(), MemValue::Str("betrayal".into()))
.edge_bind("event2", "target".into(), "character")
})
.unless_between("event1", "event2", |neg| {
neg.edge(
"recovery",
"type".into(),
MemValue::Str("trust_restored".into()),
)
})
.build();

PatternBuilder::new

Starts building a new pattern.

pub fn new(name: impl Into<String>) -> Self
ParameterTypeRequiredDefaultDescription
nameimpl Into<String>yes--Pattern name for identification.

Returns: PatternBuilder<L, V>


stage

Adds an event stage. The anchor names the event variable. Use the callback to add clauses via StageBuilder.

pub fn stage(
self,
anchor: impl Into<String>,
build: impl FnOnce(StageBuilder<L, V>) -> StageBuilder<L, V>,
) -> Self
ParameterTypeRequiredDefaultDescription
anchorimpl Into<String>yes--Event variable name for this stage.
buildFnOnce(StageBuilder) -> StageBuilderyes--Callback that adds clauses to the stage.

Returns: PatternBuilder<L, V> (chainable)


temporal

Adds an explicit temporal constraint beyond implicit stage ordering.

pub fn temporal(
self,
left: impl Into<String>,
relation: AllenRelation,
right: impl Into<String>,
) -> Self
ParameterTypeRequiredDefaultDescription
leftimpl Into<String>yes--Variable whose interval should come first.
relationAllenRelationyes--Required Allen relation.
rightimpl Into<String>yes--Variable whose interval should come second.

Returns: PatternBuilder<L, V> (chainable)


unless_between

Adds a negation window: clauses that must NOT all match between two events.

pub fn unless_between(
self,
start: impl Into<String>,
end: impl Into<String>,
build: impl FnOnce(NegationBuilder<L, V>) -> NegationBuilder<L, V>,
) -> Self
ParameterTypeRequiredDefaultDescription
startimpl Into<String>yes--Start event variable (must be a stage anchor).
endimpl Into<String>yes--End event variable (must be a stage anchor).
buildFnOnce(NegationBuilder) -> NegationBuilderyes--Callback that adds clauses to the negation.

Returns: PatternBuilder<L, V> (chainable)


unless_after

Adds a negation window with an open end (from a start event up to "now").

pub fn unless_after(
self,
start: impl Into<String>,
build: impl FnOnce(NegationBuilder<L, V>) -> NegationBuilder<L, V>,
) -> Self
ParameterTypeRequiredDefaultDescription
startimpl Into<String>yes--Start event variable.
buildFnOnce(NegationBuilder) -> NegationBuilderyes--Callback that adds clauses.

Returns: PatternBuilder<L, V> (chainable)


unless_global

Adds a negation that spans the entire pattern (first stage anchor to last stage anchor). For single-stage patterns, resolves to an open-ended window.

pub fn unless_global(
self,
build: impl FnOnce(NegationBuilder<L, V>) -> NegationBuilder<L, V>,
) -> Self
ParameterTypeRequiredDefaultDescription
buildFnOnce(NegationBuilder) -> NegationBuilderyes--Callback that adds clauses.

Returns: PatternBuilder<L, V> (chainable)


metadata

Adds a key-value metadata pair to the pattern. Metadata is propagated to Match, SiftEvent, and scored match types. Call multiple times for multiple pairs. If the same key is set twice, the last value wins.

pub fn metadata(self, key: impl Into<String>, value: impl Into<String>) -> Self
ParameterTypeRequiredDefaultDescription
keyimpl Into<String>yes--Metadata key.
valueimpl Into<String>yes--Metadata value.

Returns: PatternBuilder<L, V> (chainable)


deadline

Sets a deadline (in ticks) for partial match expiration. Active partial matches that have been alive for more than ticks ticks without completing are killed with SiftEvent::Expired during end_tick(). The deadline measures total PM lifecycle from first initiation -- when a PM advances to a new stage, created_at_tick is inherited, not reset.

pub fn deadline(self, ticks: u64) -> Self
ParameterTypeRequiredDefaultDescription
ticksu64yes--Maximum ticks before expiry. Must be >= 1.

Returns: PatternBuilder<L, V> (chainable)


private

Marks this pattern as private. Private patterns are evaluated by the engine but their matches and events are suppressed from output (evaluate(), drain_completed(), on_edge_added()). Use for composition building blocks that should not appear in results.

pub fn private(self) -> Self

Returns: PatternBuilder<L, V> (chainable)


unordered_group

Adds a group of stages that can match in any order. The closure receives an UnorderedGroupBuilder and must add at least 2 stages. The group's stage indices are computed from the current stage count.

pub fn unordered_group(
self,
build: impl FnOnce(UnorderedGroupBuilder<L, V>) -> UnorderedGroupBuilder<L, V>,
) -> Self
let pattern = PatternBuilder::<String, MemValue>::new("multi_signal")
.stage("e1", |s| {
s.edge("e1", "type".into(), MemValue::Str("trigger".into()))
})
.unordered_group(|g| {
g.stage("e2", |s| {
s.edge("e2", "type".into(), MemValue::Str("signal_a".into()))
})
.stage("e3", |s| {
s.edge("e3", "type".into(), MemValue::Str("signal_b".into()))
})
})
.stage("e4", |s| {
s.edge("e4", "type".into(), MemValue::Str("confirm".into()))
})
.build();

Returns: PatternBuilder<L, V> (chainable)


build

Consumes the builder and returns the compiled pattern. Resolves global negation bounds to first/last stage anchors.

pub fn build(self) -> Pattern<L, V>

Returns: Pattern<L, V>


UnorderedGroupBuilder<L, V>

Builder for a concurrent stage group. Obtained from PatternBuilder::unordered_group. Must contain at least 2 stages. Maximum 64 stages total in the pattern (tracked via u64 bitmask).

stage

Adds a stage to the concurrent group. Same parameters as PatternBuilder::stage.

pub fn stage(
self,
anchor: impl Into<String>,
build: impl FnOnce(StageBuilder<L, V>) -> StageBuilder<L, V>,
) -> Self

Returns: UnorderedGroupBuilder<L, V> (chainable)


StageBuilder<L, V>

Builder for a single event stage. Obtained from PatternBuilder::stage. Requires L: Clone, V: Clone.

edge

Adds a clause: source --[label]--> literal_value.

pub fn edge(
self,
source: impl Into<String>,
label: L,
value: V,
) -> Self
ParameterTypeRequiredDefaultDescription
sourceimpl Into<String>yes--Source variable name.
labelLyes--Edge label.
valueVyes--Exact target value to match.

Returns: StageBuilder<L, V> (chainable)


edge_bind

Adds a clause: source --[label]--> ?bind_var. Traverses the edge and binds the target to a variable.

pub fn edge_bind(
self,
source: impl Into<String>,
label: L,
bind_to: impl Into<String>,
) -> Self
ParameterTypeRequiredDefaultDescription
sourceimpl Into<String>yes--Source variable name.
labelLyes--Edge label.
bind_toimpl Into<String>yes--Variable name to bind the target to.

Returns: StageBuilder<L, V> (chainable)


edge_constrained

Adds a clause: source --[label]--> (constraint). The target must satisfy a ValueConstraint.

pub fn edge_constrained(
self,
source: impl Into<String>,
label: L,
constraint: ValueConstraint<V>,
) -> Self
ParameterTypeRequiredDefaultDescription
sourceimpl Into<String>yes--Source variable name.
labelLyes--Edge label.
constraintValueConstraint<V>yes--Value constraint the target must satisfy.

Returns: StageBuilder<L, V> (chainable)


edge_gt_var / edge_lt_var / edge_eq_var / edge_gte_var / edge_lte_var

Cross-stage value comparison: compare an edge's target against a previously-bound variable. The variable must have been bound by edge_bind in an earlier clause or stage. If the variable is bound to a Node (not a Value), the comparison silently fails (no match).

pub fn edge_gt_var(self, source: impl Into<String>, label: L, var_name: impl Into<String>) -> Self
pub fn edge_lt_var(self, source: impl Into<String>, label: L, var_name: impl Into<String>) -> Self
pub fn edge_eq_var(self, source: impl Into<String>, label: L, var_name: impl Into<String>) -> Self
pub fn edge_gte_var(self, source: impl Into<String>, label: L, var_name: impl Into<String>) -> Self
pub fn edge_lte_var(self, source: impl Into<String>, label: L, var_name: impl Into<String>) -> Self
ParameterTypeRequiredDefaultDescription
sourceimpl Into<String>yes--Source variable name.
labelLyes--Edge label.
var_nameimpl Into<String>yes--Name of a previously-bound variable to compare against.

Returns: StageBuilder<L, V> (chainable)


not_edge

Adds a negated clause: the edge must NOT exist.

pub fn not_edge(
self,
source: impl Into<String>,
label: L,
value: V,
) -> Self
ParameterTypeRequiredDefaultDescription
sourceimpl Into<String>yes--Source variable name.
labelLyes--Edge label.
valueVyes--Target value that must NOT be present.

Returns: StageBuilder<L, V> (chainable)


NegationBuilder<L, V>

Builder for a negation window. Obtained from PatternBuilder::unless_between, unless_after, or unless_global. Requires L: Clone, V: Clone.

edge

Adds a clause to the negation body (edge that must NOT exist in the window).

pub fn edge(
self,
source: impl Into<String>,
label: L,
value: V,
) -> Self
ParameterTypeRequiredDefaultDescription
sourceimpl Into<String>yes--Source variable name.
labelLyes--Edge label.
valueVyes--Exact target value.

Returns: NegationBuilder<L, V> (chainable)


edge_bind

Adds a binding clause to the negation body.

pub fn edge_bind(
self,
source: impl Into<String>,
label: L,
bind_to: impl Into<String>,
) -> Self
ParameterTypeRequiredDefaultDescription
sourceimpl Into<String>yes--Source variable name.
labelLyes--Edge label.
bind_toimpl Into<String>yes--Variable name to bind.

Returns: NegationBuilder<L, V> (chainable)


edge_constrained

Adds a constrained clause to the negation body.

pub fn edge_constrained(
self,
source: impl Into<String>,
label: L,
constraint: ValueConstraint<V>,
) -> Self
ParameterTypeRequiredDefaultDescription
sourceimpl Into<String>yes--Source variable name.
labelLyes--Edge label.
constraintValueConstraint<V>yes--Value constraint the target must satisfy.

Returns: NegationBuilder<L, V> (chainable)