use std::{cell::RefCell, collections::HashMap};
pub use crows_macros::config;
pub use crows_shared::Config as ExecutorConfig;
pub use crows_shared::ConstantArrivalRateConfig;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::{from_slice, to_vec};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub enum HTTPMethod {
HEAD,
GET,
POST,
PUT,
DELETE,
OPTIONS,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct HTTPRequest {
pub url: String,
pub method: HTTPMethod,
pub headers: HashMap<String, String>,
pub body: Option<String>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct HTTPError {
pub message: String,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct HTTPResponse {
pub headers: HashMap<String, String>,
pub body: String,
pub status: u16,
}
fn extract_from_return_value(value: u64) -> (u8, u32, u32) {
let status = ((value >> 56) & 0xFF) as u8;
let length = ((value >> 32) & 0x00FFFFFF) as u32;
let ptr = (value & 0xFFFFFFFF) as u32;
(status, length, ptr)
}
mod bindings {
#[link(wasm_import_module = "crows")]
extern "C" {
pub fn log(content: *mut u8, content_len: usize);
pub fn http(content: *mut u8, content_len: usize) -> u64;
pub fn consume_buffer(index: u32, content: *mut u8, content_len: usize);
pub fn set_config(content: *mut u8, content_len: usize) -> u32;
}
}
fn with_buffer<R>(f: impl FnOnce(&mut Vec<u8>) -> R) -> R {
thread_local! {
static BUFFER: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(1024));
}
BUFFER.with(|r| {
let mut buf = r.borrow_mut();
buf.clear();
f(&mut buf)
})
}
pub fn http_request(
url: String,
method: HTTPMethod,
headers: HashMap<String, String>,
body: String,
) -> Result<HTTPResponse, HTTPError> {
let body = Some(body);
let request = HTTPRequest {
method,
url,
headers,
body,
};
call_host_function(&request, |buf| unsafe {
bindings::http(buf.as_mut_ptr(), buf.len())
})
}
fn call_host_function<T, R, E>(arguments: &T, f: impl FnOnce(&mut Vec<u8>) -> u64) -> Result<R, E>
where
T: Serialize,
R: DeserializeOwned,
E: DeserializeOwned,
{
let mut encoded = to_vec(arguments).unwrap();
let response = f(&mut encoded);
let (status, length, index) = extract_from_return_value(response);
let mut buf = encoded;
buf.clear();
buf.reserve_exact(length as usize);
unsafe {
bindings::consume_buffer(index, buf.as_mut_ptr(), length as usize);
buf.set_len(length as usize);
}
if status == 0 {
Ok(from_slice(&buf).expect("Couldn't decode message from the host"))
} else {
Err(from_slice(&buf).expect("Couldn't decode message from the host"))
}
}
pub fn __set_config(config: ExecutorConfig) -> u32 {
let mut encoded = to_vec(&config).unwrap();
unsafe { bindings::set_config(encoded.as_mut_ptr(), encoded.len()) }
}