varpulis_sase/types.rs
1//! Core SASE+ types and constants
2
3use std::sync::Arc;
4use std::time::Duration;
5
6use rustc_hash::FxHashMap;
7use varpulis_core::{Event, Value};
8
9use crate::clock::Timestamp;
10
11/// Shared event reference for efficient cloning in pattern matching.
12/// Using Arc allows multiple pattern runs to share the same event data
13/// without expensive deep copies.
14pub type SharedEvent = Arc<Event>;
15
16/// Safety cap on events accumulated in a single Kleene closure.
17/// With n events the ZDD enumerates up to 2^n - 1 combinations.
18/// 20 events → ~1 M combinations (safe); 30 → ~1 B (OOM risk).
19pub const MAX_KLEENE_EVENTS: u32 = 20;
20
21/// Safety cap on results emitted by `enumerate_with_filter`.
22/// Prevents unbounded memory growth when the deferred predicate
23/// passes most combinations of a large Kleene closure.
24pub const MAX_ENUMERATION_RESULTS: usize = 10_000;
25
26// ============================================================================
27// PATTERN EXPRESSION AST
28// ============================================================================
29
30/// A SASE+ pattern expression
31#[derive(Debug, Clone)]
32pub enum SasePattern {
33 /// Match a single event type with optional predicate.
34 Event {
35 /// The event type name to match.
36 event_type: String,
37 /// Optional filter predicate.
38 predicate: Option<Predicate>,
39 /// Optional alias for capturing the matched event.
40 alias: Option<String>,
41 },
42 /// Sequence: SEQ(A, B, C) - events must occur in order
43 Seq(Vec<SasePattern>),
44 /// Conjunction: AND(A, B) - both must occur (any order)
45 And(Box<SasePattern>, Box<SasePattern>),
46 /// Disjunction: OR(A, B) - either must occur
47 Or(Box<SasePattern>, Box<SasePattern>),
48 /// Negation: NOT(A) - event must NOT occur
49 Not(Box<SasePattern>),
50 /// Kleene plus: A+ (one or more occurrences)
51 KleenePlus(Box<SasePattern>),
52 /// Kleene star: A* (zero or more occurrences)
53 KleeneStar(Box<SasePattern>),
54 /// Temporal constraint: pattern within duration
55 Within(Box<SasePattern>, Duration),
56}
57
58/// Predicate for event filtering
59#[derive(Debug, Clone)]
60pub enum Predicate {
61 /// Field comparison: field op value
62 Compare {
63 /// Event field name to compare.
64 field: String,
65 /// Comparison operator.
66 op: CompareOp,
67 /// Constant value to compare against.
68 value: Value,
69 },
70 /// Field reference comparison: field op alias.field
71 CompareRef {
72 /// Event field name on the current event.
73 field: String,
74 /// Comparison operator.
75 op: CompareOp,
76 /// Alias of the previously captured event.
77 ref_alias: String,
78 /// Field name on the referenced captured event.
79 ref_field: String,
80 },
81 /// Logical AND
82 And(Box<Predicate>, Box<Predicate>),
83 /// Logical OR
84 Or(Box<Predicate>, Box<Predicate>),
85 /// Logical NOT
86 Not(Box<Predicate>),
87 /// Custom expression
88 Expr(Box<varpulis_core::ast::Expr>),
89}
90
91/// Comparison operators for predicate evaluation.
92///
93/// Used in SASE+ predicates to filter events based on field values.
94///
95/// # Example
96///
97/// ```rust,no_run
98/// use varpulis_sase::{CompareOp, Predicate};
99/// use varpulis_core::Value;
100///
101/// let pred = Predicate::Compare {
102/// field: "temperature".to_string(),
103/// op: CompareOp::Gt,
104/// value: Value::Float(100.0),
105/// };
106/// ```
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum CompareOp {
109 /// Equality (`==`)
110 Eq,
111 /// Inequality (`!=`)
112 NotEq,
113 /// Less than (`<`)
114 Lt,
115 /// Less than or equal (`<=`)
116 Le,
117 /// Greater than (`>`)
118 Gt,
119 /// Greater than or equal (`>=`)
120 Ge,
121}
122
123/// A stack entry for Kleene closure handling
124#[derive(Debug, Clone)]
125pub struct StackEntry {
126 /// Captured event (Arc for efficient sharing across runs)
127 pub event: SharedEvent,
128 /// Alias for this capture
129 pub alias: Option<String>,
130 /// Timestamp of capture
131 pub timestamp: Timestamp,
132}
133
134/// Event selection strategy
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
136pub enum SelectionStrategy {
137 /// Skip-till-any-match: most permissive, can skip irrelevant events
138 SkipTillAnyMatch,
139 /// Skip-till-next-match: contiguous matching for Kleene
140 SkipTillNextMatch,
141 /// Strict contiguous: no skipping allowed
142 StrictContiguous,
143}
144
145/// Result of pattern matching
146#[derive(Debug, Clone)]
147pub struct MatchResult {
148 /// All captured events by alias (Arc for zero-copy access)
149 pub captured: FxHashMap<String, SharedEvent>,
150 /// The event stack (ordered sequence of matches)
151 pub stack: Vec<StackEntry>,
152 /// Match duration
153 pub duration: Duration,
154}
155
156/// SASE+ Pattern Matching Engine
157/// Global negation condition for invalidating active runs
158#[derive(Debug, Clone)]
159pub struct GlobalNegation {
160 /// Event type that triggers negation
161 pub event_type: String,
162 /// Optional predicate (with access to captured events)
163 pub predicate: Option<Predicate>,
164}
165
166/// Time semantics for the engine
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
168pub enum TimeSemantics {
169 /// Processing time: use wall-clock time (no watermarks needed)
170 #[default]
171 ProcessingTime,
172 /// Event time: use event timestamps with watermark-based window completion
173 EventTime,
174}
175
176/// Engine statistics snapshot.
177#[derive(Debug, Clone)]
178pub struct SaseStats {
179 /// Number of currently active partial-match runs.
180 pub active_runs: usize,
181 /// Number of partition buckets in use.
182 pub partitions: usize,
183 /// Number of states in the compiled NFA.
184 pub nfa_states: usize,
185}
186
187/// Snapshot of an active SASE run for forecast computation.
188#[derive(Debug, Clone)]
189pub struct RunSnapshot {
190 /// Current NFA state index.
191 pub current_state: usize,
192 /// When this run started (nanoseconds since epoch).
193 pub started_at_ns: i64,
194}