use std::fmt::Debug;
use glaredb_error::{DbError, Result};
use crate::execution::operators::{PollExecute, PollFinalize};
pub trait Effects {
fn handle_execute(&mut self, op_idx: usize) -> Result<PollExecute>;
fn handle_finalize(&mut self, op_idx: usize) -> Result<PollFinalize>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StackControlFlow {
Continue,
Finished,
Pending,
}
#[derive(Debug, Clone, Copy)]
enum Instruction {
ExecuteOperator {
operator_idx: usize,
is_pipeline_start: bool,
},
FinalizeOperator { operator_idx: usize },
}
#[derive(Debug)]
pub struct ExecutionStack {
num_operators: usize,
instructions: Vec<Instruction>,
}
impl ExecutionStack {
pub fn new(num_operators: usize) -> Self {
assert_ne!(0, num_operators);
let mut instructions = Vec::with_capacity(num_operators);
instructions.push(Instruction::ExecuteOperator {
operator_idx: 0,
is_pipeline_start: true,
});
ExecutionStack {
num_operators,
instructions,
}
}
pub fn pop_next<H>(&mut self, effects: &mut H) -> Result<StackControlFlow>
where
H: Effects,
{
let instr = match self.instructions.pop() {
Some(instr) => instr,
None => return Ok(StackControlFlow::Finished),
};
match instr {
Instruction::ExecuteOperator {
operator_idx,
is_pipeline_start,
} => {
let poll = effects.handle_execute(operator_idx)?;
match poll {
PollExecute::Ready => {
if is_pipeline_start {
self.instructions.push(instr);
}
if operator_idx != self.num_operators - 1 {
self.instructions.push(Instruction::ExecuteOperator {
operator_idx: operator_idx + 1,
is_pipeline_start: false,
});
}
Ok(StackControlFlow::Continue)
}
PollExecute::Pending => {
self.instructions.push(instr);
Ok(StackControlFlow::Pending)
}
PollExecute::NeedsMore => {
Ok(StackControlFlow::Continue)
}
PollExecute::HasMore => {
self.instructions.push(Instruction::ExecuteOperator {
operator_idx,
is_pipeline_start,
});
if operator_idx != self.num_operators - 1 {
self.instructions.push(Instruction::ExecuteOperator {
operator_idx: operator_idx + 1,
is_pipeline_start: false,
});
} else {
return Err(DbError::new("Last operator returned HasMore"));
}
Ok(StackControlFlow::Continue)
}
PollExecute::Exhausted => {
self.instructions.clear();
if operator_idx == self.num_operators - 1 {
return Err(DbError::new("Last operator returned Exhausted"));
}
self.instructions.push(Instruction::FinalizeOperator {
operator_idx: operator_idx + 1,
});
self.instructions.push(Instruction::ExecuteOperator {
operator_idx: operator_idx + 1,
is_pipeline_start: false,
});
Ok(StackControlFlow::Continue)
}
}
}
Instruction::FinalizeOperator { operator_idx } => {
assert_ne!(0, operator_idx, "attempted to finalize operator at index 0");
let poll = effects.handle_finalize(operator_idx)?;
match poll {
PollFinalize::Finalized => {
if operator_idx == self.num_operators - 1 {
Ok(StackControlFlow::Finished)
} else {
self.instructions.push(Instruction::FinalizeOperator {
operator_idx: operator_idx + 1,
});
Ok(StackControlFlow::Continue)
}
}
PollFinalize::NeedsDrain => {
if operator_idx == self.num_operators - 1 {
return Err(DbError::new("Last operator returned NeedsDrain"));
}
self.instructions.push(Instruction::ExecuteOperator {
operator_idx,
is_pipeline_start: true,
});
Ok(StackControlFlow::Continue)
}
PollFinalize::Pending => {
self.instructions.push(instr);
Ok(StackControlFlow::Pending)
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug)]
struct TestEffects {
execute: Option<(usize, PollExecute)>,
finalize: Option<(usize, PollFinalize)>,
}
impl TestEffects {
fn execute(expected_idx: usize, poll: PollExecute) -> Self {
TestEffects {
execute: Some((expected_idx, poll)),
finalize: None,
}
}
fn finalize(expected_idx: usize, poll: PollFinalize) -> Self {
TestEffects {
execute: None,
finalize: Some((expected_idx, poll)),
}
}
}
impl Effects for TestEffects {
fn handle_execute(&mut self, op_idx: usize) -> Result<PollExecute> {
let (expected, poll) = self.execute.unwrap();
assert_eq!(expected, op_idx);
Ok(poll)
}
fn handle_finalize(&mut self, op_idx: usize) -> Result<PollFinalize> {
let (expected, poll) = self.finalize.unwrap();
assert_eq!(expected, op_idx);
Ok(poll)
}
}
fn pop_next(stack: &mut ExecutionStack, mut effects: impl Effects) -> StackControlFlow {
stack.pop_next(&mut effects).unwrap()
}
#[test]
fn stack_execution_resets() {
let mut stack = ExecutionStack::new(3);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
}
#[test]
fn stack_execution_pending() {
let mut stack = ExecutionStack::new(2);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Pending));
assert_eq!(out, StackControlFlow::Pending);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
}
#[test]
fn stack_execution_needs_more() {
let mut stack = ExecutionStack::new(2);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::NeedsMore));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
}
#[test]
fn stack_execution_has_more() {
let mut stack = ExecutionStack::new(3);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::HasMore));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
}
#[test]
fn stack_execution_has_more_then_needs_more() {
let mut stack = ExecutionStack::new(3);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::HasMore));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::NeedsMore));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
}
#[test]
fn stack_execution_exhaust_first_finalize_last() {
let mut stack = ExecutionStack::new(2);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Exhausted));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(
&mut stack,
TestEffects::finalize(1, PollFinalize::Finalized),
);
assert_eq!(out, StackControlFlow::Finished);
}
#[test]
fn stack_execution_exhaust_first_finalize_second_then_last() {
let mut stack = ExecutionStack::new(3);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Exhausted));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(
&mut stack,
TestEffects::finalize(1, PollFinalize::Finalized),
);
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(
&mut stack,
TestEffects::finalize(2, PollFinalize::Finalized),
);
assert_eq!(out, StackControlFlow::Finished);
}
#[test]
fn stack_execution_exhaust_first_needs_drain_second() {
let mut stack = ExecutionStack::new(3);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Exhausted));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(
&mut stack,
TestEffects::finalize(1, PollFinalize::NeedsDrain),
);
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Exhausted));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(
&mut stack,
TestEffects::finalize(2, PollFinalize::Finalized),
);
assert_eq!(out, StackControlFlow::Finished);
}
#[test]
fn stack_execution_multiple_has_more() {
let mut stack = ExecutionStack::new(4);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::HasMore));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::HasMore));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(3, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(3, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(3, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
}
#[test]
fn stack_execution_propagate_finalize_through_many() {
let mut stack = ExecutionStack::new(4);
let out = pop_next(&mut stack, TestEffects::execute(0, PollExecute::Exhausted));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(1, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(2, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(&mut stack, TestEffects::execute(3, PollExecute::Ready));
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(
&mut stack,
TestEffects::finalize(1, PollFinalize::Finalized),
);
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(
&mut stack,
TestEffects::finalize(2, PollFinalize::Finalized),
);
assert_eq!(out, StackControlFlow::Continue);
let out = pop_next(
&mut stack,
TestEffects::finalize(3, PollFinalize::Finalized),
);
assert_eq!(out, StackControlFlow::Finished);
}
}