use std::sync::Arc;
use crate::iteration::comprehension::ir::Program;
use super::coord_stream::CoordinateStream;
use super::instance::{KernelScope, ScopedKernelInstance};
use super::scope_once::scope_once_with;
pub struct ScopedKernelStream<K: KernelScope> {
coord_stream: CoordinateStream,
parent: K,
}
impl<K: KernelScope> ScopedKernelStream<K> {
pub(crate) fn new(program: Arc<Program>, parent: K) -> Self {
let coord_stream = CoordinateStream::new(program);
Self { coord_stream, parent }
}
pub fn advance(&mut self) -> Option<ScopedKernelInstance<K::Scoped>> {
let coords = self.coord_stream.advance()?;
let instance = scope_once_with(&self.parent, &coords);
Some(instance)
}
}
impl<K: KernelScope> Iterator for ScopedKernelStream<K> {
type Item = ScopedKernelInstance<K::Scoped>;
fn next(&mut self) -> Option<Self::Item> {
self.advance()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::iteration::comprehension::ast::Comprehension;
use crate::iteration::comprehension::source::{LiteralValue, Source};
use crate::iteration::comprehension::strategies::{Tuple, TupleValue};
use crate::iteration::comprehension::surfaces::compile;
#[derive(Debug, Clone)]
struct MockKernel(String);
impl KernelScope for MockKernel {
type Scoped = (String, Vec<(String, TupleValue)>);
fn scope(&self, coords: &Tuple) -> Self::Scoped {
(self.0.clone(), coords.bindings.clone())
}
}
fn clause(name: &str, vs: &[i64]) -> Comprehension {
Comprehension::clause(
name,
Source::Literal {
values: vs.iter().map(|n| LiteralValue::Int(*n)).collect(),
},
)
}
#[test]
fn advance_produces_scoped_instances() {
let compiled = compile(&clause("k", &[1, 2, 3]));
let parent = MockKernel("p".into());
let mut stream = compiled.scoped_kernel_stream(parent);
let mut count = 0;
while let Some(inst) = stream.advance() {
assert_eq!(inst.scoped.0, "p");
assert_eq!(inst.coords.bindings.len(), 1);
count += 1;
}
assert_eq!(count, 3);
}
#[test]
fn dispense_order_matches_coord_stream() {
let compiled = compile(&clause("k", &[10, 20, 30]));
let parent = MockKernel("p".into());
let coord_values: Vec<TupleValue> = compiled
.coordinate_stream()
.map(|t| t.bindings[0].1.clone())
.collect();
let scoped_values: Vec<TupleValue> = compiled
.scoped_kernel_stream(parent)
.map(|inst| inst.coords.bindings[0].1.clone())
.collect();
assert_eq!(coord_values, scoped_values);
}
}