use std::future::Future;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use serde::de::DeserializeOwned;
use crate::host::abi;
use crate::{Error, Result};
pub struct Payload(serde_json::Value);
pub fn take_input(ptr: i32, len: i32) -> Vec<u8> {
abi::read_owned(ptr, len)
}
pub fn parse_invocation(bytes: &[u8]) -> Result<(String, Payload)> {
let mut v: serde_json::Value =
serde_json::from_slice(bytes).map_err(|e| Error::Codec(e.to_string()))?;
let handler = v
.get("handler")
.and_then(|h| h.as_str())
.ok_or_else(|| Error::Host("invocation missing handler".into()))?
.to_owned();
let payload = v
.get_mut("payload")
.map(serde_json::Value::take)
.unwrap_or(serde_json::Value::Null);
Ok((handler, Payload(payload)))
}
pub fn from_payload<T: DeserializeOwned>(payload: Payload) -> Result<T> {
serde_json::from_value(payload.0).map_err(|e| Error::Codec(e.to_string()))
}
pub fn unknown_handler(name: &str) -> Error {
Error::Host(format!("unknown handler: {name}"))
}
pub fn block_on<F: Future<Output = Result<()>>>(fut: F) -> Result<()> {
fn clone(_: *const ()) -> RawWaker {
RawWaker::new(std::ptr::null(), &VTABLE)
}
fn noop(_: *const ()) {}
static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, noop, noop, noop);
let waker = unsafe { Waker::from_raw(RawWaker::new(std::ptr::null(), &VTABLE)) };
let mut cx = Context::from_waker(&waker);
let mut fut = fut;
let mut fut = unsafe { std::pin::Pin::new_unchecked(&mut fut) };
match fut.as_mut().poll(&mut cx) {
Poll::Ready(out) => out,
Poll::Pending => {
panic!("sprout handler awaited a non-host future; sprouts may not run their own async runtime")
}
}
}
pub fn finish(result: Result<()>) -> i64 {
let env = match result {
Ok(()) => serde_json::json!({ "ok": true, "value": null }),
Err(e) => {
let (kind, message) = match e {
Error::Host(m) => ("Host", m),
Error::Codec(m) => ("Codec", m),
Error::Denied(m) => ("Denied", m),
};
serde_json::json!({ "ok": false, "error": { "kind": kind, "message": message } })
}
};
let bytes = serde_json::to_vec(&env).unwrap_or_else(|_| b"{\"ok\":false}".to_vec());
let len = bytes.len() as i32;
let ptr = abi::__cotyledon_alloc(len);
unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr as *mut u8, bytes.len()) };
abi::pack(ptr, len)
}