use crate::{ffi::module_run_v0 as ffi, Error, ErrorCode};
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
#[doc(hidden)]
pub use ffi::API as FFI_API;
pub use crate::ffi::entrypoints::module_run::ModuleRunFn;
pub struct Function {
handle: ffi::FunctionHandle,
}
impl Function {
pub fn new(fn_module: &str, fn_name: &str) -> Result<Self, Error> {
ffi::create_function(ffi::FunctionSource::NamedModule, fn_module, fn_name)
.map_err(Error::from)
.map(|handle| Self { handle })
}
pub fn with_local_fn(fn_name: &str) -> Result<Self, Error> {
ffi::create_function(ffi::FunctionSource::OwnModule, "", fn_name)
.map_err(Error::from)
.map(|handle| Self { handle })
}
pub(crate) fn handle(&self) -> ffi::FunctionHandle {
self.handle
}
}
impl Drop for Function {
fn drop(&mut self) {
ffi::remove_function(self.handle).unwrap();
}
}
pub fn blocking_launch(function: &Function, input: &[u8]) -> Result<Vec<u8>, Error> {
let handle = ffi::blocking_launch(function.handle(), input).map_err(Error::from)?;
let ready = ffi::is_ready(handle).map_err(Error::from)?;
assert!(ready.is_ready);
let mut out_buffer = vec![0; ready.size as usize];
ffi::retrieve(handle, &mut out_buffer)?;
Ok(out_buffer)
}
pub fn launch(function: &Function, input: &[u8]) -> impl Future<Output = Result<Vec<u8>, Error>> {
struct LaunchFuture(Result<ffi::RequestHandle, ErrorCode>);
impl Future for LaunchFuture {
type Output = Result<Vec<u8>, Error>;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.0 {
Ok(handle) => match ffi::is_ready(handle) {
Ok(ffi::IsReady {
is_ready: false, ..
}) => Poll::Pending,
Ok(ffi::IsReady {
is_ready: true,
size,
..
}) => {
let mut buffer = vec![0; size as usize];
match ffi::retrieve(handle, &mut buffer) {
Err(err) => Poll::Ready(Err(err.into())),
Ok(()) => Poll::Ready(Ok(buffer)),
}
}
Err(error_code) => Poll::Ready(Err(Error::from(error_code))),
},
Err(error_code) => Poll::Ready(Err(Error::from(error_code))),
}
}
}
LaunchFuture(ffi::launch(function.handle(), input))
}