use crate::backend::{private, BackendError, OutputBuffers, TimedDispatchResult};
pub trait PendingDispatch: private::Sealed + Send + Sync {
fn is_ready(&self) -> bool;
fn await_result(self: Box<Self>) -> Result<Vec<Vec<u8>>, BackendError>;
fn await_timed_result(self: Box<Self>) -> Result<TimedDispatchResult, BackendError> {
let started = std::time::Instant::now();
let outputs = self.await_result()?;
Ok(TimedDispatchResult {
outputs,
wall_ns: crate::backend::checked_elapsed_wall_ns(
started,
"pending dispatch retirement",
)?,
device_ns: None,
enqueue_ns: None,
wait_ns: None,
})
}
fn await_result_into(self: Box<Self>, outputs: &mut OutputBuffers) -> Result<(), BackendError> {
let result = self.await_result()?;
crate::backend::dispatch_result::replace_output_buffers_preserving_slots(result, outputs);
Ok(())
}
fn await_result_async(
self: Box<Self>,
) -> impl std::future::Future<Output = Result<Vec<Vec<u8>>, BackendError>> + Send
where
Self: Sized,
{
async { self.await_result() }
}
}
pub(crate) struct ReadyPending {
pub(crate) outputs: Vec<Vec<u8>>,
}
impl private::Sealed for ReadyPending {}
impl PendingDispatch for ReadyPending {
fn is_ready(&self) -> bool {
true
}
fn await_result(self: Box<Self>) -> Result<Vec<Vec<u8>>, BackendError> {
Ok(self.outputs)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pending_dispatch_default_into_preserves_output_slots() {
let mut outputs = vec![Vec::with_capacity(8)];
let outputs_addr = outputs.as_ptr() as usize;
let slot_addr = outputs[0].as_ptr() as usize;
Box::new(ReadyPending {
outputs: vec![vec![1, 2, 3]],
})
.await_result_into(&mut outputs)
.expect("Fix: ready pending output should write into caller storage");
assert_eq!(outputs, vec![vec![1, 2, 3]]);
assert_eq!(outputs.as_ptr() as usize, outputs_addr);
assert_eq!(outputs[0].as_ptr() as usize, slot_addr);
}
}