polydat/kernel/
api_impl.rs1use crate::kernel::{Dataflow, GkKernel, Metadata, Construction};
14use crate::node::{PortType, Value};
15
16impl Metadata for GkKernel {
17 #[inline]
18 fn find_input(&self, name: &str) -> Option<usize> {
19 self.program().find_input(name)
20 }
21
22 #[inline]
23 fn input_names(&self) -> Vec<String> {
24 self.program().input_names()
25 }
26
27 #[inline]
28 fn output_names(&self) -> Vec<String> {
29 self.program().output_names().iter().map(|s| s.to_string()).collect()
30 }
31
32 #[inline]
33 fn coord_count(&self) -> usize {
34 self.program().coord_count()
35 }
36
37 #[inline]
38 fn input_port_type(&self, name: &str) -> Option<PortType> {
39 self.program().input_port_type(name)
40 }
41}
42
43impl Dataflow for GkKernel {
44 #[inline]
45 fn set_wire_idx(&mut self, idx: usize, value: Value) {
46 self.state().set_input(idx, value);
47 }
48
49 #[inline]
50 fn get_wire_idx(&self, idx: usize) -> Value {
51 self.state_ref().get_input(idx)
52 }
53}
54
55impl Construction for GkKernel {
56 type Error = crate::subcontext::ContractViolation;
57
58 fn root(matter: crate::subcontext::GkMatter<'_>) -> Result<Self, Self::Error> {
59 use crate::subcontext::GkMatterInner;
60 match matter.inner {
61 GkMatterInner::Source(s) => {
62 crate::dsl::compile::compile_gk_with_libs_and_limit(
63 &s.body,
64 s.options.workload_dir.as_deref(),
65 s.options.gk_lib_paths,
66 &s.options.required_outputs,
67 s.options.strict,
68 s.options.context_label.as_deref().unwrap_or(&s.label),
69 s.options.cursor_limit,
70 )
71 .map_err(crate::subcontext::ContractViolation::Compile)
72 }
73 GkMatterInner::Statements(s) => {
74 let file = crate::dsl::ast::GkFile { statements: s.statements };
79 crate::dsl::compile::compile_ast_with_libs(
80 &file,
81 s.options.workload_dir.as_deref(),
82 s.options.gk_lib_paths,
83 &s.options.required_outputs,
84 s.options.strict,
85 s.options.context_label.as_deref().unwrap_or(&s.label),
86 )
87 .map_err(crate::subcontext::ContractViolation::Compile)
88 }
89 GkMatterInner::Program(p) => {
90 let mut k = GkKernel::from_program(p.program);
91 for (var, value) in p.iter_bindings {
92 if let Some(idx) = k.program().find_input(var) {
93 k.state().set_input(idx, value.clone());
94 }
95 }
96 Ok(k)
97 }
98 }
99 }
100
101 fn subscope(
102 &self,
103 matter: crate::subcontext::GkMatter<'_>,
104 ) -> Result<Self, Self::Error> {
105 GkKernel::build_subscope(self, matter)
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use crate::dsl::compile::compile_gk;
114
115 #[test]
117 fn dataflow_indexed_set_get() {
118 let mut k = compile_gk(
119 "input cycle: u64\nconst x := 7\n"
120 ).unwrap();
121 k.set_wire(0_usize, Value::U64(42));
123 assert_eq!(k.get_wire(0_usize), Some(Value::U64(42)));
124 }
125
126 #[test]
128 fn dataflow_named_set_get() {
129 let mut k = compile_gk(
130 "input cycle: u64\nextern n: u64\n"
131 ).unwrap();
132 k.set_wire("n", Value::U64(5));
133 match k.get_wire("n") {
134 Some(Value::U64(5)) => {}
135 other => panic!("expected U64(5), got {other:?}"),
136 }
137 }
138
139 #[test]
141 fn dataflow_string_key() {
142 let mut k = compile_gk(
143 "input cycle: u64\nextern n: u64\n"
144 ).unwrap();
145 let name = String::from("n");
146 k.set_wire(&name, Value::U64(99));
147 assert_eq!(k.get_wire(name.clone()), Some(Value::U64(99)));
148 }
149
150 #[test]
152 fn dataflow_unknown_name_safe() {
153 let mut k = compile_gk("input cycle: u64\n").unwrap();
154 assert!(!k.set_wire("nonexistent", Value::U64(1)));
155 assert!(k.get_wire("nonexistent").is_none());
156 }
157
158 #[test]
160 fn metadata_listings() {
161 let k = compile_gk(
162 "input (cycle: u64, thread: u64)\nextern n: u64\nconst x := 7\n"
163 ).unwrap();
164 let inputs: Vec<String> = k.input_names();
165 assert!(inputs.iter().any(|s| s == "cycle"));
166 assert!(inputs.iter().any(|s| s == "n"));
167 assert_eq!(k.coord_count(), 2); assert!(k.find_input("n").is_some());
169 assert_eq!(k.input_port_type("n"), Some(PortType::U64));
170 }
171
172 #[test]
176 fn construction_symmetric_paths() {
177 let root_opts = crate::subcontext::CompileOptions {
178 workload_dir: None,
179 gk_lib_paths: Vec::new(),
180 strict: false,
181 required_outputs: Vec::new(),
182 context_label: Some("root".to_string()),
183 cursor_limit: None,
184 ..Default::default()
185 };
186 let root_matter = crate::subcontext::GkMatter::builder()
187 .label("root")
188 .source("input cycle: u64\nshared flag := 0\n")
189 .options(root_opts)
190 .build()
191 .expect("matter build");
192 let root = <GkKernel as Construction>::root(root_matter)
193 .expect("root from source matter");
194
195 let sub_opts = crate::subcontext::CompileOptions {
196 workload_dir: None,
197 gk_lib_paths: Vec::new(),
198 strict: false,
199 required_outputs: Vec::new(),
200 context_label: Some("sub".to_string()),
201 cursor_limit: None,
202 ..Default::default()
203 };
204 let sub_matter = crate::subcontext::GkMatter::builder()
205 .label("sub")
206 .source("input cycle: u64\n")
207 .options(sub_opts)
208 .build()
209 .expect("matter build");
210 let _sub = root
211 .subscope(sub_matter)
212 .expect("subscope from source matter");
213 }
214
215 #[test]
219 fn construction_root_from_program() {
220 let template = compile_gk("input cycle: u64\nextern n: u64\n").unwrap();
221 let program = template.program().clone();
222 let matter = crate::subcontext::GkMatter::builder()
223 .program(program)
224 .build()
225 .expect("matter build");
226 let mut root = <GkKernel as Construction>::root(matter)
227 .expect("root from program matter");
228 root.set_wire("n", Value::U64(13));
229 assert_eq!(root.get_wire("n"), Some(Value::U64(13)));
230 }
231
232 #[test]
234 fn builder_rejects_multiple_forms() {
235 let template = compile_gk("input cycle: u64\n").unwrap();
236 match crate::subcontext::GkMatter::builder()
237 .source("input cycle: u64\n")
238 .program(template.program().clone())
239 .build()
240 {
241 Err(msg) => assert!(msg.contains("multiple"), "expected multiple-forms error, got: {msg}"),
242 Ok(_) => panic!("multiple forms must error"),
243 }
244 }
245
246 #[test]
248 fn builder_rejects_empty() {
249 match crate::subcontext::GkMatter::builder().build() {
250 Err(msg) => assert!(msg.contains("no input form"), "expected no-form error, got: {msg}"),
251 Ok(_) => panic!("empty matter must error"),
252 }
253 }
254}