1use std::collections::{BTreeMap, VecDeque};
7use std::ffi::c_void;
8use std::sync::Arc;
9
10use crate::config::GraphConfig;
11use crate::context::{Context, Options};
12use crate::kernel::{Contract, KernelInstance, PortTable};
13use crate::packet::Packet;
14use crate::runtime::GraphShared;
15use crate::status::{Error, Result};
16use crate::timestamp::Timestamp;
17
18pub struct KernelRunner {
19 kernel: KernelInstance,
20 contract: Contract,
21 context: Context,
22 opened: bool,
23 open_error: Option<Error>,
24 pending_inputs: Vec<Option<Packet>>,
25 outputs: Vec<VecDeque<Packet>>,
26}
27
28impl KernelRunner {
29 pub fn new(kernel_name: &str, input_ports: usize, output_ports: usize) -> Result<Self> {
30 let inputs = Arc::new(PortTable::build(
31 &(0..input_ports)
32 .map(|i| format!("in{i}"))
33 .collect::<Vec<_>>(),
34 "kernel runner input_ports",
35 )?);
36 let outputs = Arc::new(PortTable::build(
37 &(0..output_ports)
38 .map(|i| format!("out{i}"))
39 .collect::<Vec<_>>(),
40 "kernel runner output_ports",
41 )?);
42 let mut contract = Contract::new(inputs.clone(), outputs.clone());
43 unsafe {
44 KernelInstance::fill_contract(
45 kernel_name,
46 &mut contract as *mut Contract as *mut c_void,
47 )?;
48 }
49 if let Some(error) = contract.take_error() {
50 return Err(Error::InvalidArg(format!(
51 "kernel runner contract: {error}"
52 )));
53 }
54 let kernel = KernelInstance::create(kernel_name)?;
55 let shared = Arc::new(GraphShared::new(GraphConfig::default()));
56 let context = Context::new(
57 "kernel_runner".into(),
58 kernel_name.into(),
59 inputs,
60 outputs,
61 Arc::new(Options::new(serde_yaml::Value::Mapping(
62 serde_yaml::Mapping::new(),
63 ))),
64 Arc::new(BTreeMap::new()),
65 shared,
66 );
67 Ok(Self {
68 kernel,
69 contract,
70 context,
71 opened: false,
72 open_error: None,
73 pending_inputs: (0..input_ports).map(|_| None).collect(),
74 outputs: (0..output_ports).map(|_| VecDeque::new()).collect(),
75 })
76 }
77
78 pub fn contract(&self) -> &Contract {
79 &self.contract
80 }
81
82 pub fn set_options_json(&mut self, json: &str) -> Result<()> {
83 if self.opened {
84 return Err(Error::State(
85 "kernel runner options must be set before open".into(),
86 ));
87 }
88 let value: serde_yaml::Value = serde_json::from_str(json)
89 .map_err(|error| Error::InvalidArg(format!("kernel runner options: {error}")))?;
90 self.context.options = Arc::new(Options::new(value));
91 Ok(())
92 }
93
94 pub fn set_side_packet(&mut self, name: &str, packet: Packet) -> Result<()> {
95 if self.opened {
96 return Err(Error::State(
97 "kernel runner side packets must be set before open".into(),
98 ));
99 }
100 Arc::make_mut(&mut self.context.side_packets).insert(name.into(), packet);
101 Ok(())
102 }
103
104 pub fn open(&mut self) -> Result<()> {
105 if let Some(error) = &self.open_error {
106 return Err(error.clone());
107 }
108 if self.opened {
109 return Ok(());
110 }
111 for name in &self.contract.required_side_packets {
112 if !self.context.side_packets.contains_key(name) {
113 return Err(Error::InvalidArg(format!(
114 "kernel runner missing required side packet `{name}`"
115 )));
116 }
117 }
118 self.context.reset();
119 self.context.input_ts = Timestamp::unstarted();
120 let status = unsafe { self.kernel.open(&mut self.context as *mut _ as *mut c_void) };
121 if status != 0 {
122 let error = self.context.take_error(status);
123 self.context.discard_staging();
124 self.open_error = Some(error.clone());
125 return Err(error);
126 }
127 self.opened = true;
130 if let Err(error) = self.validate_outputs() {
131 self.context.discard_staging();
132 self.open_error = Some(error.clone());
133 return Err(error);
134 }
135 for (output, staged) in self.outputs.iter_mut().zip(&mut self.context.staging) {
136 output.extend(staged.drain(..));
137 }
138 Ok(())
139 }
140
141 pub fn process(
142 &mut self,
143 inputs: Vec<Option<Packet>>,
144 timestamp: Timestamp,
145 ) -> Result<Vec<Vec<Packet>>> {
146 self.open()?;
147 if inputs.len() != self.context.inputs.len() {
148 return Err(Error::InvalidArg(format!(
149 "kernel runner expected {} inputs, got {}",
150 self.context.inputs.len(),
151 inputs.len()
152 )));
153 }
154 self.context.reset();
155 for (port, packet) in inputs.iter().enumerate() {
156 if let Some(packet) = packet {
157 let expected = self.contract.input_types[port];
158 if expected != 0 && packet.type_id() != expected {
159 return Err(Error::InvalidArg(format!(
160 "kernel runner input {port} type mismatch: expected {}, got {}",
161 expected,
162 packet.type_id()
163 )));
164 }
165 }
166 }
167 self.context.inputs = inputs
168 .into_iter()
169 .map(|packet| {
170 packet.map(|packet| {
171 if packet.timestamp() == Timestamp::unset() {
172 packet.at(timestamp)
173 } else {
174 packet
175 }
176 })
177 })
178 .collect();
179 self.context.input_ts = timestamp;
180 let status = unsafe {
181 self.kernel
182 .process(&mut self.context as *mut _ as *mut c_void)
183 };
184 self.context.clear_inputs();
187 if status != 0 {
188 let error = self.context.take_error(status);
189 self.context.discard_staging();
190 return Err(error);
191 }
192 if let Err(error) = self.validate_outputs() {
193 self.context.discard_staging();
194 return Err(error);
195 }
196 let staging: Vec<Vec<Packet>> = self
197 .context
198 .staging
199 .iter_mut()
200 .map(std::mem::take)
201 .collect();
202 for (port, packets) in staging.iter().enumerate() {
203 self.outputs[port].extend(packets.iter().cloned());
204 }
205 Ok(staging)
206 }
207
208 pub fn add_input(&mut self, port: usize, packet: Packet) -> Result<()> {
209 let slot = self
210 .pending_inputs
211 .get_mut(port)
212 .ok_or_else(|| Error::InvalidArg(format!("input port index {port} is out of range")))?;
213 if slot.is_some() {
214 return Err(Error::State(format!(
215 "kernel runner input port {port} already has a packet for the next process call"
216 )));
217 }
218 *slot = Some(packet);
219 Ok(())
220 }
221
222 pub fn process_pending(&mut self, timestamp: Timestamp) -> Result<Vec<Vec<Packet>>> {
223 let inputs = std::mem::take(&mut self.pending_inputs);
224 let result = self.process(inputs, timestamp);
225 self.pending_inputs = (0..self.context.inputs.len()).map(|_| None).collect();
226 result
227 }
228
229 pub fn try_output(&mut self, port: usize) -> Result<Option<Packet>> {
230 self.outputs
231 .get_mut(port)
232 .ok_or_else(|| Error::InvalidArg(format!("output port index {port} is out of range")))
233 .map(VecDeque::pop_front)
234 }
235
236 pub fn close(&mut self) -> Result<Vec<Vec<Packet>>> {
240 self.pending_inputs.fill(None);
243 if !self.opened {
244 return Ok((0..self.context.staging.len())
245 .map(|_| Vec::new())
246 .collect());
247 }
248 self.context.reset();
249 self.context.close_reason = if self.open_error.is_some() {
250 crate::runtime::CLOSE_ERROR
251 } else {
252 crate::runtime::CLOSE_NORMAL
253 };
254 let status = unsafe {
255 self.context.input_ts = Timestamp::done();
256 self.kernel
257 .close(&mut self.context as *mut _ as *mut c_void)
258 };
259 self.opened = false;
260 if let Some(error) = &self.open_error {
261 self.context.discard_staging();
262 return Err(error.clone());
263 }
264 if status != 0 {
265 let error = self.context.take_error(status);
266 self.context.discard_staging();
267 return Err(error);
268 }
269 if let Err(error) = self.validate_outputs() {
270 self.context.discard_staging();
271 return Err(error);
272 }
273 let staging: Vec<Vec<Packet>> = self
274 .context
275 .staging
276 .iter_mut()
277 .map(std::mem::take)
278 .collect();
279 for (port, packets) in staging.iter().enumerate() {
280 self.outputs[port].extend(packets.iter().cloned());
281 }
282 Ok(staging)
283 }
284
285 fn validate_outputs(&self) -> Result<()> {
286 for (port, packets) in self.context.staging.iter().enumerate() {
287 let expected = self.contract.output_types[port];
288 if expected != 0 {
289 if let Some(packet) = packets.iter().find(|packet| packet.type_id() != expected) {
290 return Err(Error::Kernel(format!(
291 "kernel runner output {port} type mismatch: expected {}, got {}",
292 expected,
293 packet.type_id()
294 )));
295 }
296 }
297 }
298 Ok(())
299 }
300}
301
302impl Drop for KernelRunner {
303 fn drop(&mut self) {
304 let _ = self.close();
305 }
306}