pub mod activation;
mod api;
mod api_impl;
pub(crate) mod engines;
pub mod intern;
pub mod interp;
mod manifest;
mod opt;
mod program;
mod scope;
mod state;
pub mod subcontext;
pub use activation::{Activation, CursorSlice, TraversalStream};
pub(crate) use api::SharedKernel;
pub(crate) use api::internals::KernelInternals;
pub use api::{Construction, Dataflow, Kernel, KernelProgram, Metadata, WireKey, WriteError};
pub use engines::*;
pub use intern::{StaticInterner, static_pair};
pub use manifest::{ManifestEntry, extract_manifest};
pub use opt::KernelOptLevel;
pub use program::*;
pub use scope::{ScopeCoord, format_scope_coordinate_path};
pub use state::*;
use crate::ast::Value;
#[derive(Debug, Clone)]
pub enum WireSource {
Input(usize),
NodeOutput(usize, usize),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InputKind {
Coordinate,
IterationExtern,
ExternalWrite,
}
#[derive(Debug, Clone)]
pub struct InputDef {
pub name: String,
pub default: Value,
pub port_type: crate::ast::PortType,
pub kind: InputKind,
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
use std::sync::Arc;
#[test]
fn capture_inputs_persist_across_set_inputs() {
let program = Arc::new(PolydatProgram::with_inputs(
vec![],
vec![],
vec![
InputDef {
name: "cycle".into(),
default: Value::U64(0),
port_type: crate::ast::PortType::U64,
kind: InputKind::Coordinate,
},
InputDef {
name: "balance".into(),
default: Value::F64(0.0),
port_type: crate::ast::PortType::F64,
kind: InputKind::ExternalWrite,
},
InputDef {
name: "auth_token".into(),
default: Value::Str("anonymous".into()),
port_type: crate::ast::PortType::Str,
kind: InputKind::ExternalWrite,
},
],
1, HashMap::new(),
Vec::new(),
"",
"(test)",
crate::kernel::CompileLedger::new(),
));
let mut state = program.create_state();
assert_eq!(state.get_input(1), Value::F64(0.0));
assert_eq!(state.get_input(2), Value::Str("anonymous".into()));
state.set_input(1, Value::F64(1234.56));
state.set_input(2, Value::Str("token_abc".into()));
assert_eq!(state.get_input(1), Value::F64(1234.56));
assert_eq!(state.get_input(2), Value::Str("token_abc".into()));
state.set_inputs(&[42]);
assert_eq!(state.get_input(1), Value::F64(1234.56));
assert_eq!(state.get_input(2), Value::Str("token_abc".into()));
}
#[test]
fn reset_inputs_restores_capture_defaults() {
let program = Arc::new(PolydatProgram::with_inputs(
vec![],
vec![],
vec![
InputDef {
name: "cycle".into(),
default: Value::U64(0),
port_type: crate::ast::PortType::U64,
kind: InputKind::Coordinate,
},
InputDef {
name: "token".into(),
default: Value::Str("anon".into()),
port_type: crate::ast::PortType::Str,
kind: InputKind::ExternalWrite,
},
],
1,
HashMap::new(),
Vec::new(),
"",
"(test)",
crate::kernel::CompileLedger::new(),
));
let mut state = program.create_state();
state.set_input(1, Value::Str("alice".into()));
assert_eq!(state.get_input(1), Value::Str("alice".into()));
state.reset_inputs_from(1);
assert_eq!(state.get_input(1), Value::Str("anon".into()));
}
#[test]
fn invalidate_all_keeps_inputs_and_reset_restores_defaults() {
let program = Arc::new(PolydatProgram::with_inputs(
vec![],
vec![],
vec![
InputDef {
name: "cycle".into(),
default: Value::U64(0),
port_type: crate::ast::PortType::U64,
kind: InputKind::Coordinate,
},
InputDef {
name: "token".into(),
default: Value::Str("anon".into()),
port_type: crate::ast::PortType::Str,
kind: InputKind::ExternalWrite,
},
],
1,
HashMap::new(),
Vec::new(),
"",
"(test)",
crate::kernel::CompileLedger::new(),
));
let mut state = program.create_state();
state.set_inputs(&[42]);
state.set_input(1, Value::Str("alice".into()));
state.invalidate_all();
assert_eq!(state.get_input(0), Value::U64(42));
assert_eq!(state.get_input(1), Value::Str("alice".into()));
state.reset_inputs_from(0);
assert_eq!(state.get_input(0), Value::U64(0));
assert_eq!(state.get_input(1), Value::Str("anon".into()));
}
struct ConfigWireTestNode {
meta: crate::ast::NodeMeta,
}
impl ConfigWireTestNode {
fn new() -> Self {
use crate::ast::{Port, Slot};
Self {
meta: crate::ast::NodeMeta {
name: "config_test".into(),
outs: vec![Port::u64("output")],
ins: vec![
Slot::Wire(Port::u64("config_param").config()),
Slot::Wire(Port::u64("data_input")),
],
},
}
}
}
impl crate::ast::PolydatNode for ConfigWireTestNode {
fn meta(&self) -> &crate::ast::NodeMeta {
&self.meta
}
fn eval(&self, inputs: &[Value], outputs: &mut [Value]) {
let config = inputs[0].as_u64();
let data = inputs[1].as_u64();
outputs[0] = Value::U64(config.wrapping_add(data));
}
}
#[test]
fn wire_cost_no_warning_when_config_is_init_time() {
use crate::compile::assembly::{PolydatAssembler, WireRef};
use crate::dsl::events::CompileEventLog;
use crate::library::identity::ConstU64;
use crate::library::identity::Identity;
let mut asm = PolydatAssembler::new(vec!["cycle".into()]);
asm.add_node("config_val", Box::new(ConstU64::new(42)), vec![]);
asm.add_node(
"hashed",
Box::new(Identity::new(crate::ast::PortType::U64)),
vec![WireRef::input("cycle")],
);
asm.add_node(
"test_node",
Box::new(ConfigWireTestNode::new()),
vec![WireRef::node("config_val"), WireRef::node("hashed")],
);
asm.add_output("result", WireRef::node("test_node"));
let mut log = CompileEventLog::new();
let k = asm.compile_with_log(Some(&mut log)).unwrap();
let _program = k.into_program();
let warnings: Vec<_> = log
.events()
.iter()
.filter(|e| {
matches!(
e,
crate::dsl::events::CompileEvent::ConfigWireCycleWarning { .. }
)
})
.collect();
assert!(
warnings.is_empty(),
"no warning expected when config wire is init-time: {warnings:?}"
);
}
#[test]
fn wire_cost_warning_when_config_is_cycle_time() {
use crate::compile::assembly::{PolydatAssembler, WireRef};
use crate::dsl::events::CompileEventLog;
use crate::library::identity::Identity;
let mut asm = PolydatAssembler::new(vec!["cycle".into()]);
asm.add_node(
"hashed",
Box::new(Identity::new(crate::ast::PortType::U64)),
vec![WireRef::input("cycle")],
);
asm.add_node(
"test_node",
Box::new(ConfigWireTestNode::new()),
vec![
WireRef::node("hashed"), WireRef::input("cycle"), ],
);
asm.add_output("result", WireRef::node("test_node"));
let mut log = CompileEventLog::new();
let _k = asm.compile_with_log(Some(&mut log)).unwrap();
let warnings: Vec<_> = log
.events()
.iter()
.filter(|e| {
matches!(
e,
crate::dsl::events::CompileEvent::ConfigWireCycleWarning { .. }
)
})
.collect();
assert_eq!(
warnings.len(),
1,
"expected exactly one config wire warning: {warnings:?}"
);
}
#[test]
fn wire_cost_warning_when_config_is_coordinate_direct() {
use crate::compile::assembly::{PolydatAssembler, WireRef};
use crate::dsl::events::CompileEventLog;
let mut asm = PolydatAssembler::new(vec!["cycle".into()]);
asm.add_node(
"test_node",
Box::new(ConfigWireTestNode::new()),
vec![
WireRef::input("cycle"), WireRef::input("cycle"), ],
);
asm.add_output("result", WireRef::node("test_node"));
let mut log = CompileEventLog::new();
let _k = asm.compile_with_log(Some(&mut log)).unwrap();
let warnings: Vec<_> = log
.events()
.iter()
.filter(|e| {
matches!(
e,
crate::dsl::events::CompileEvent::ConfigWireCycleWarning { .. }
)
})
.collect();
assert_eq!(warnings.len(), 1, "config wire from coordinate should warn");
}
#[test]
fn wire_cost_no_warning_data_wire_from_cycle() {
use crate::compile::assembly::{PolydatAssembler, WireRef};
use crate::dsl::events::CompileEventLog;
use crate::library::identity::ConstU64;
let mut asm = PolydatAssembler::new(vec!["cycle".into()]);
asm.add_node("config_val", Box::new(ConstU64::new(10)), vec![]);
asm.add_node(
"test_node",
Box::new(ConfigWireTestNode::new()),
vec![
WireRef::node("config_val"), WireRef::input("cycle"), ],
);
asm.add_output("result", WireRef::node("test_node"));
let mut log = CompileEventLog::new();
let _k = asm.compile_with_log(Some(&mut log)).unwrap();
let warnings: Vec<_> = log
.events()
.iter()
.filter(|e| {
matches!(
e,
crate::dsl::events::CompileEvent::ConfigWireCycleWarning { .. }
)
})
.collect();
assert!(warnings.is_empty(), "data wire from cycle should not warn");
}
#[test]
fn wire_cost_diamond_config_from_init() {
use crate::compile::assembly::{PolydatAssembler, WireRef};
use crate::dsl::events::CompileEventLog;
use crate::library::identity::ConstU64;
use crate::library::identity::Identity;
let mut asm = PolydatAssembler::new(vec!["cycle".into()]);
asm.add_node("a", Box::new(ConstU64::new(5)), vec![]);
asm.add_node("b", Box::new(ConstU64::new(3)), vec![]);
asm.add_node(
"inner",
Box::new(ConfigWireTestNode::new()),
vec![WireRef::node("a"), WireRef::node("b")],
);
asm.add_node(
"hashed",
Box::new(Identity::new(crate::ast::PortType::U64)),
vec![WireRef::input("cycle")],
);
asm.add_node(
"outer",
Box::new(ConfigWireTestNode::new()),
vec![
WireRef::node("inner"), WireRef::node("hashed"), ],
);
asm.add_output("result", WireRef::node("outer"));
let mut log = CompileEventLog::new();
let _k = asm.compile_with_log(Some(&mut log)).unwrap();
let warnings: Vec<_> = log
.events()
.iter()
.filter(|e| {
matches!(
e,
crate::dsl::events::CompileEvent::ConfigWireCycleWarning { .. }
)
})
.collect();
assert!(
warnings.is_empty(),
"init-time derived config should not warn: {warnings:?}"
);
}
#[test]
fn wire_cost_diamond_config_from_mixed() {
use crate::compile::assembly::{PolydatAssembler, WireRef};
use crate::dsl::events::CompileEventLog;
use crate::library::identity::ConstU64;
let mut asm = PolydatAssembler::new(vec!["cycle".into()]);
asm.add_node("five", Box::new(ConstU64::new(5)), vec![]);
asm.add_node(
"mixer",
Box::new(ConfigWireTestNode::new()),
vec![
WireRef::node("five"), WireRef::input("cycle"), ],
);
asm.add_node(
"outer",
Box::new(ConfigWireTestNode::new()),
vec![
WireRef::node("mixer"), WireRef::input("cycle"), ],
);
asm.add_output("result", WireRef::node("outer"));
let mut log = CompileEventLog::new();
let _k = asm.compile_with_log(Some(&mut log)).unwrap();
let warnings: Vec<_> = log
.events()
.iter()
.filter(|e| {
matches!(
e,
crate::dsl::events::CompileEvent::ConfigWireCycleWarning { .. }
)
})
.collect();
assert_eq!(
warnings.len(),
1,
"exactly one warning for outer's config: {warnings:?}"
);
}
}