#[cfg(target_arch = "wasm32")]
#[link(wasm_import_module = "flaron/v1")]
extern "C" {
pub fn req_method() -> i64;
pub fn req_url() -> i64;
pub fn req_header_get(name_ptr: i32, name_len: i32) -> i64;
pub fn req_body() -> i64;
pub fn resp_set_status(status: i32);
pub fn resp_header_set(name_ptr: i32, name_len: i32, val_ptr: i32, val_len: i32);
pub fn resp_body_set(body_ptr: i32, body_len: i32);
pub fn beam_fetch(url_ptr: i32, url_len: i32, opts_ptr: i32, opts_len: i32) -> i64;
pub fn log_info(msg_ptr: i32, msg_len: i32);
pub fn log_warn(msg_ptr: i32, msg_len: i32);
pub fn log_error(msg_ptr: i32, msg_len: i32);
pub fn crypto_hash(args_ptr: i32, args_len: i32) -> i64;
pub fn crypto_hmac(args_ptr: i32, args_len: i32) -> i64;
pub fn crypto_sign_jwt(args_ptr: i32, args_len: i32) -> i64;
pub fn crypto_encrypt_aes(args_ptr: i32, args_len: i32) -> i64;
pub fn crypto_decrypt_aes(args_ptr: i32, args_len: i32) -> i64;
pub fn crypto_random_bytes(length: i32) -> i64;
pub fn encoding_base64_encode(data_ptr: i32, data_len: i32) -> i64;
pub fn encoding_base64_decode(data_ptr: i32, data_len: i32) -> i64;
pub fn encoding_hex_encode(data_ptr: i32, data_len: i32) -> i64;
pub fn encoding_hex_decode(data_ptr: i32, data_len: i32) -> i64;
pub fn encoding_url_encode(data_ptr: i32, data_len: i32) -> i64;
pub fn encoding_url_decode(data_ptr: i32, data_len: i32) -> i64;
pub fn id_uuid(args_ptr: i32, args_len: i32) -> i64;
pub fn id_ulid() -> i64;
pub fn id_nanoid(length: i32) -> i64;
pub fn id_ksuid() -> i64;
pub fn snowflake_id() -> i64;
pub fn timestamp(args_ptr: i32, args_len: i32) -> i64;
pub fn spark_get(key_ptr: i32, key_len: i32) -> i64;
pub fn spark_set(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32, ttl_secs: i32) -> i32;
pub fn spark_delete(key_ptr: i32, key_len: i32);
pub fn spark_list() -> i64;
pub fn spark_pull(origin_ptr: i32, origin_len: i32, keys_ptr: i32, keys_len: i32) -> i32;
pub fn plasma_get(key_ptr: i32, key_len: i32) -> i64;
pub fn plasma_set(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32) -> i32;
pub fn plasma_delete(key_ptr: i32, key_len: i32) -> i32;
pub fn plasma_increment(key_ptr: i32, key_len: i32, delta: i64) -> i64;
pub fn plasma_decrement(key_ptr: i32, key_len: i32, delta: i64) -> i64;
pub fn plasma_list() -> i64;
pub fn secret_get(key_ptr: i32, key_len: i32) -> i64;
pub fn ws_send(data_ptr: i32, data_len: i32) -> i32;
pub fn ws_close_conn(code: i32);
pub fn ws_conn_id() -> i64;
pub fn ws_event_type() -> i64;
pub fn ws_event_data() -> i64;
pub fn ws_close_code() -> i32;
}
#[cfg(not(target_arch = "wasm32"))]
pub use host_mock::*;
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
pub mod test_host {
use std::cell::RefCell;
use std::collections::HashMap;
#[derive(Default, Debug)]
pub struct MockHost {
pub req_method: Option<String>,
pub req_url: Option<String>,
pub req_headers: HashMap<String, String>,
pub req_body: Option<Vec<u8>>,
pub resp_status: Option<i32>,
pub resp_headers: Vec<(String, String)>,
pub resp_body: Option<Vec<u8>>,
pub beam_response: Option<Vec<u8>>,
pub last_beam_url: Option<String>,
pub last_beam_opts: Option<String>,
pub logs: Vec<(&'static str, String)>,
pub crypto_hash_response: Option<String>,
pub crypto_hmac_response: Option<String>,
pub crypto_sign_jwt_response: Option<String>,
pub crypto_encrypt_aes_response: Option<String>,
pub crypto_decrypt_aes_response: Option<Vec<u8>>,
pub crypto_random_bytes_response: Option<String>,
pub last_crypto_hash_args: Option<String>,
pub last_crypto_hmac_args: Option<String>,
pub last_crypto_sign_jwt_args: Option<String>,
pub last_crypto_encrypt_aes_args: Option<String>,
pub last_crypto_decrypt_aes_args: Option<String>,
pub last_random_bytes_length: Option<i32>,
pub encoding_base64_encode_response: Option<String>,
pub encoding_base64_decode_response: Option<Vec<u8>>,
pub encoding_hex_encode_response: Option<String>,
pub encoding_hex_decode_response: Option<Vec<u8>>,
pub encoding_url_encode_response: Option<String>,
pub encoding_url_decode_response: Option<String>,
pub last_encoding_base64_encode_input: Option<Vec<u8>>,
pub last_encoding_base64_decode_input: Option<String>,
pub last_encoding_hex_encode_input: Option<Vec<u8>>,
pub last_encoding_hex_decode_input: Option<String>,
pub last_encoding_url_encode_input: Option<String>,
pub last_encoding_url_decode_input: Option<String>,
pub id_uuid_response: Option<String>,
pub id_ulid_response: Option<String>,
pub id_nanoid_response: Option<String>,
pub id_ksuid_response: Option<String>,
pub snowflake_id_response: Option<String>,
pub last_id_uuid_args: Option<String>,
pub last_nanoid_length: Option<i32>,
pub timestamp_response: Option<String>,
pub last_timestamp_args: Option<String>,
pub spark_store: HashMap<String, (Vec<u8>, u32)>,
pub spark_set_error: i32,
pub spark_pull_result: i32,
pub spark_deletes: Vec<String>,
pub spark_pull_calls: Vec<(String, String)>,
pub last_spark_set: Option<(String, Vec<u8>, i32)>,
pub plasma_store: HashMap<String, Vec<u8>>,
pub plasma_counters: HashMap<String, i64>,
pub plasma_set_error: i32,
pub plasma_delete_error: i32,
pub plasma_increment_error: bool,
pub plasma_deletes: Vec<String>,
pub last_plasma_set: Option<(String, Vec<u8>)>,
pub last_plasma_increment: Option<(String, i64)>,
pub last_plasma_decrement: Option<(String, i64)>,
pub secrets: HashMap<String, Vec<u8>>,
pub last_secret_get: Option<String>,
pub ws_send_error: i32,
pub ws_conn_id: Option<String>,
pub ws_event_type: Option<String>,
pub ws_event_data: Option<Vec<u8>>,
pub ws_close_code: i32,
pub ws_closes: Vec<i32>,
pub ws_sends: Vec<Vec<u8>>,
}
thread_local! {
static MOCK: RefCell<MockHost> = RefCell::new(MockHost::default());
}
pub fn with_mock<R>(f: impl FnOnce(&mut MockHost) -> R) -> R {
MOCK.with(|m| f(&mut m.borrow_mut()))
}
pub fn read_mock<R>(f: impl FnOnce(&MockHost) -> R) -> R {
MOCK.with(|m| f(&m.borrow()))
}
pub fn reset() {
MOCK.with(|m| *m.borrow_mut() = MockHost::default());
crate::mem::reset_arena();
}
}
#[cfg(not(target_arch = "wasm32"))]
mod host_mock {
use super::test_host::with_mock;
use crate::mem;
fn write_arena(data: &[u8]) -> i64 {
if data.is_empty() {
let offset = mem::guest_alloc(1);
if offset == 0 {
return 0;
}
return mem::encode_ptr_len(offset as u32, 0);
}
let offset = mem::guest_alloc(data.len() as i32);
if offset == 0 {
return 0;
}
mem::arena_write_at(offset as usize, data);
mem::encode_ptr_len(offset as u32, data.len() as u32)
}
fn read_arg(offset: i32, len: i32) -> Vec<u8> {
if len <= 0 {
return Vec::new();
}
mem::arena_read_at(offset as usize, len as usize)
}
fn read_arg_str(offset: i32, len: i32) -> String {
String::from_utf8_lossy(&read_arg(offset, len)).into_owned()
}
pub unsafe fn req_method() -> i64 {
with_mock(|m| match m.req_method.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
})
}
pub unsafe fn req_url() -> i64 {
with_mock(|m| match m.req_url.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
})
}
pub unsafe fn req_header_get(name_ptr: i32, name_len: i32) -> i64 {
let name = read_arg_str(name_ptr, name_len);
with_mock(|m| match m.req_headers.get(&name) {
Some(v) => write_arena(v.as_bytes()),
None => 0,
})
}
pub unsafe fn req_body() -> i64 {
with_mock(|m| match m.req_body.as_deref() {
Some(b) => write_arena(b),
None => 0,
})
}
pub unsafe fn resp_set_status(status: i32) {
with_mock(|m| m.resp_status = Some(status));
}
pub unsafe fn resp_header_set(name_ptr: i32, name_len: i32, val_ptr: i32, val_len: i32) {
let name = read_arg_str(name_ptr, name_len);
let val = read_arg_str(val_ptr, val_len);
with_mock(|m| m.resp_headers.push((name, val)));
}
pub unsafe fn resp_body_set(body_ptr: i32, body_len: i32) {
let body = read_arg(body_ptr, body_len);
with_mock(|m| m.resp_body = Some(body));
}
pub unsafe fn beam_fetch(url_ptr: i32, url_len: i32, opts_ptr: i32, opts_len: i32) -> i64 {
let url = read_arg_str(url_ptr, url_len);
let opts = read_arg_str(opts_ptr, opts_len);
with_mock(|m| {
m.last_beam_url = Some(url);
m.last_beam_opts = Some(opts);
match m.beam_response.as_deref() {
Some(b) => write_arena(b),
None => 0,
}
})
}
pub unsafe fn log_info(msg_ptr: i32, msg_len: i32) {
let msg = read_arg_str(msg_ptr, msg_len);
with_mock(|m| m.logs.push(("info", msg)));
}
pub unsafe fn log_warn(msg_ptr: i32, msg_len: i32) {
let msg = read_arg_str(msg_ptr, msg_len);
with_mock(|m| m.logs.push(("warn", msg)));
}
pub unsafe fn log_error(msg_ptr: i32, msg_len: i32) {
let msg = read_arg_str(msg_ptr, msg_len);
with_mock(|m| m.logs.push(("error", msg)));
}
pub unsafe fn crypto_hash(args_ptr: i32, args_len: i32) -> i64 {
let args = read_arg_str(args_ptr, args_len);
with_mock(|m| {
m.last_crypto_hash_args = Some(args);
match m.crypto_hash_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn crypto_hmac(args_ptr: i32, args_len: i32) -> i64 {
let args = read_arg_str(args_ptr, args_len);
with_mock(|m| {
m.last_crypto_hmac_args = Some(args);
match m.crypto_hmac_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn crypto_sign_jwt(args_ptr: i32, args_len: i32) -> i64 {
let args = read_arg_str(args_ptr, args_len);
with_mock(|m| {
m.last_crypto_sign_jwt_args = Some(args);
match m.crypto_sign_jwt_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn crypto_encrypt_aes(args_ptr: i32, args_len: i32) -> i64 {
let args = read_arg_str(args_ptr, args_len);
with_mock(|m| {
m.last_crypto_encrypt_aes_args = Some(args);
match m.crypto_encrypt_aes_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn crypto_decrypt_aes(args_ptr: i32, args_len: i32) -> i64 {
let args = read_arg_str(args_ptr, args_len);
with_mock(|m| {
m.last_crypto_decrypt_aes_args = Some(args);
match m.crypto_decrypt_aes_response.as_deref() {
Some(b) => write_arena(b),
None => 0,
}
})
}
pub unsafe fn crypto_random_bytes(length: i32) -> i64 {
with_mock(|m| {
m.last_random_bytes_length = Some(length);
match m.crypto_random_bytes_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn encoding_base64_encode(data_ptr: i32, data_len: i32) -> i64 {
let input = read_arg(data_ptr, data_len);
with_mock(|m| {
m.last_encoding_base64_encode_input = Some(input);
match m.encoding_base64_encode_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn encoding_base64_decode(data_ptr: i32, data_len: i32) -> i64 {
let input = read_arg_str(data_ptr, data_len);
with_mock(|m| {
m.last_encoding_base64_decode_input = Some(input);
match m.encoding_base64_decode_response.as_deref() {
Some(b) => write_arena(b),
None => 0,
}
})
}
pub unsafe fn encoding_hex_encode(data_ptr: i32, data_len: i32) -> i64 {
let input = read_arg(data_ptr, data_len);
with_mock(|m| {
m.last_encoding_hex_encode_input = Some(input);
match m.encoding_hex_encode_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn encoding_hex_decode(data_ptr: i32, data_len: i32) -> i64 {
let input = read_arg_str(data_ptr, data_len);
with_mock(|m| {
m.last_encoding_hex_decode_input = Some(input);
match m.encoding_hex_decode_response.as_deref() {
Some(b) => write_arena(b),
None => 0,
}
})
}
pub unsafe fn encoding_url_encode(data_ptr: i32, data_len: i32) -> i64 {
let input = read_arg_str(data_ptr, data_len);
with_mock(|m| {
m.last_encoding_url_encode_input = Some(input);
match m.encoding_url_encode_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn encoding_url_decode(data_ptr: i32, data_len: i32) -> i64 {
let input = read_arg_str(data_ptr, data_len);
with_mock(|m| {
m.last_encoding_url_decode_input = Some(input);
match m.encoding_url_decode_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn id_uuid(args_ptr: i32, args_len: i32) -> i64 {
let args = read_arg_str(args_ptr, args_len);
with_mock(|m| {
m.last_id_uuid_args = Some(args);
match m.id_uuid_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn id_ulid() -> i64 {
with_mock(|m| match m.id_ulid_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
})
}
pub unsafe fn id_nanoid(length: i32) -> i64 {
with_mock(|m| {
m.last_nanoid_length = Some(length);
match m.id_nanoid_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn id_ksuid() -> i64 {
with_mock(|m| match m.id_ksuid_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
})
}
pub unsafe fn snowflake_id() -> i64 {
with_mock(|m| match m.snowflake_id_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
})
}
pub unsafe fn timestamp(args_ptr: i32, args_len: i32) -> i64 {
let args = read_arg_str(args_ptr, args_len);
with_mock(|m| {
m.last_timestamp_args = Some(args);
match m.timestamp_response.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
}
})
}
pub unsafe fn spark_get(key_ptr: i32, key_len: i32) -> i64 {
let key = read_arg_str(key_ptr, key_len);
with_mock(|m| match m.spark_store.get(&key) {
Some((value, ttl)) => {
let mut payload = ttl.to_le_bytes().to_vec();
payload.extend_from_slice(value);
write_arena(&payload)
}
None => 0,
})
}
pub unsafe fn spark_set(
key_ptr: i32,
key_len: i32,
val_ptr: i32,
val_len: i32,
ttl_secs: i32,
) -> i32 {
let key = read_arg_str(key_ptr, key_len);
let val = read_arg(val_ptr, val_len);
with_mock(|m| {
m.last_spark_set = Some((key.clone(), val.clone(), ttl_secs));
if m.spark_set_error != 0 {
return m.spark_set_error;
}
m.spark_store.insert(key, (val, ttl_secs.max(0) as u32));
0
})
}
pub unsafe fn spark_delete(key_ptr: i32, key_len: i32) {
let key = read_arg_str(key_ptr, key_len);
with_mock(|m| {
m.spark_store.remove(&key);
m.spark_deletes.push(key);
});
}
pub unsafe fn spark_list() -> i64 {
with_mock(|m| {
let keys: Vec<&String> = m.spark_store.keys().collect();
let json = serde_json::to_string(&keys).unwrap_or_else(|_| "[]".into());
write_arena(json.as_bytes())
})
}
pub unsafe fn spark_pull(
origin_ptr: i32,
origin_len: i32,
keys_ptr: i32,
keys_len: i32,
) -> i32 {
let origin = read_arg_str(origin_ptr, origin_len);
let keys = read_arg_str(keys_ptr, keys_len);
with_mock(|m| {
m.spark_pull_calls.push((origin, keys));
m.spark_pull_result
})
}
pub unsafe fn plasma_get(key_ptr: i32, key_len: i32) -> i64 {
let key = read_arg_str(key_ptr, key_len);
with_mock(|m| match m.plasma_store.get(&key) {
Some(v) => write_arena(v),
None => 0,
})
}
pub unsafe fn plasma_set(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32) -> i32 {
let key = read_arg_str(key_ptr, key_len);
let val = read_arg(val_ptr, val_len);
with_mock(|m| {
m.last_plasma_set = Some((key.clone(), val.clone()));
if m.plasma_set_error != 0 {
return m.plasma_set_error;
}
m.plasma_store.insert(key, val);
0
})
}
pub unsafe fn plasma_delete(key_ptr: i32, key_len: i32) -> i32 {
let key = read_arg_str(key_ptr, key_len);
with_mock(|m| {
m.plasma_deletes.push(key.clone());
if m.plasma_delete_error != 0 {
return m.plasma_delete_error;
}
m.plasma_store.remove(&key);
0
})
}
pub unsafe fn plasma_increment(key_ptr: i32, key_len: i32, delta: i64) -> i64 {
let key = read_arg_str(key_ptr, key_len);
with_mock(|m| {
m.last_plasma_increment = Some((key.clone(), delta));
if m.plasma_increment_error {
return 0;
}
let counter = m.plasma_counters.entry(key).or_insert(0);
*counter += delta;
let bytes = counter.to_le_bytes();
write_arena(&bytes)
})
}
pub unsafe fn plasma_decrement(key_ptr: i32, key_len: i32, delta: i64) -> i64 {
let key = read_arg_str(key_ptr, key_len);
with_mock(|m| {
m.last_plasma_decrement = Some((key.clone(), delta));
if m.plasma_increment_error {
return 0;
}
let counter = m.plasma_counters.entry(key).or_insert(0);
*counter -= delta;
let bytes = counter.to_le_bytes();
write_arena(&bytes)
})
}
pub unsafe fn plasma_list() -> i64 {
with_mock(|m| {
let keys: Vec<&String> = m.plasma_store.keys().collect();
let json = serde_json::to_string(&keys).unwrap_or_else(|_| "[]".into());
write_arena(json.as_bytes())
})
}
pub unsafe fn secret_get(key_ptr: i32, key_len: i32) -> i64 {
let key = read_arg_str(key_ptr, key_len);
with_mock(|m| {
m.last_secret_get = Some(key.clone());
match m.secrets.get(&key) {
Some(v) => write_arena(v),
None => 0,
}
})
}
pub unsafe fn ws_send(data_ptr: i32, data_len: i32) -> i32 {
let data = read_arg(data_ptr, data_len);
with_mock(|m| {
m.ws_sends.push(data);
m.ws_send_error
})
}
pub unsafe fn ws_close_conn(code: i32) {
with_mock(|m| m.ws_closes.push(code));
}
pub unsafe fn ws_conn_id() -> i64 {
with_mock(|m| match m.ws_conn_id.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
})
}
pub unsafe fn ws_event_type() -> i64 {
with_mock(|m| match m.ws_event_type.as_deref() {
Some(s) => write_arena(s.as_bytes()),
None => 0,
})
}
pub unsafe fn ws_event_data() -> i64 {
with_mock(|m| match m.ws_event_data.as_deref() {
Some(b) => write_arena(b),
None => 0,
})
}
pub unsafe fn ws_close_code() -> i32 {
with_mock(|m| m.ws_close_code)
}
}