use serde::{Deserialize, Serialize};
use crate::iteration::comprehension::source::Source;
use crate::iteration::comprehension::strategy::{StrategyName, ZipMode};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "op", rename_all = "snake_case")]
pub enum Op {
PushClause { name: String, source: Source },
Cartesian { n: usize },
Zip { n: usize, mode: ZipMode },
Union { n: usize },
Filter { predicate: String },
OrderStreaming {
kind: OrderStreamingKind,
truncation: Option<u64>,
},
OrderMaterialize {
strategy: StrategyName,
truncation: Option<u64>,
indexed: bool,
input_index_fn: Option<crate::iteration::comprehension::metadata::IndexFn>,
},
Dispense,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum OrderStreamingKind {
Lex,
}
impl Op {
pub fn stack_effect(&self) -> (usize, usize) {
match self {
Op::PushClause { .. } => (0, 1),
Op::Cartesian { n } => (*n, 1),
Op::Zip { n, .. } => (*n, 1),
Op::Union { n } => (*n, 1),
Op::Filter { .. } => (1, 1),
Op::OrderStreaming { .. } => (1, 1),
Op::OrderMaterialize { .. } => (1, 1),
Op::Dispense => (1, 0),
}
}
pub fn is_barrier(&self) -> bool {
matches!(
self,
Op::OrderMaterialize { .. } | Op::Zip { mode: ZipMode::Cycle, .. }
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stack_effect_basics() {
assert_eq!(Op::PushClause {
name: "k".into(),
source: Source::Literal { values: vec![] },
}.stack_effect(), (0, 1));
assert_eq!(Op::Cartesian { n: 3 }.stack_effect(), (3, 1));
assert_eq!(Op::Dispense.stack_effect(), (1, 0));
}
#[test]
fn barrier_classification() {
assert!(Op::OrderMaterialize {
strategy: StrategyName::Halton,
truncation: Some(10),
indexed: true,
input_index_fn: None,
}.is_barrier());
assert!(Op::Zip { n: 2, mode: ZipMode::Cycle }.is_barrier());
assert!(!Op::Zip { n: 2, mode: ZipMode::Strict }.is_barrier());
assert!(!Op::OrderStreaming {
kind: OrderStreamingKind::Lex,
truncation: None,
}.is_barrier());
}
#[test]
fn serde_round_trip() {
let op = Op::OrderMaterialize {
strategy: StrategyName::Halton,
truncation: Some(50),
indexed: true,
input_index_fn: Some(crate::iteration::comprehension::metadata::IndexFn::Lattice {
axis_sizes: vec![10, 5],
}),
};
let json = serde_json::to_string(&op).unwrap();
let back: Op = serde_json::from_str(&json).unwrap();
assert_eq!(op, back);
}
}