use serde::de::DeserializeOwned;
use crate::bridge::{self, HoroscopeInput, LunarChartInput, QueryInput, SolarChartInput};
use crate::error::BridgeError;
fn hand_over(s: String) -> u64 {
let bytes = s.into_bytes();
let len = bytes.len() as u64;
let ptr = Box::leak(bytes.into_boxed_slice()).as_mut_ptr() as u64;
(ptr << 32) | len
}
fn error_result(err: &BridgeError) -> u64 {
hand_over(crate::dto::error_json(err))
}
unsafe fn read_input(ptr: *const u8, len: u32) -> Result<String, BridgeError> {
let slice = unsafe { std::slice::from_raw_parts(ptr, len as usize) };
String::from_utf8(slice.to_vec())
.map_err(|e| BridgeError::invalid_argument(format!("invalid input: not valid UTF-8: {e}")))
}
unsafe fn run<T, F>(ptr: *const u8, len: u32, compute: F) -> u64
where
T: DeserializeOwned,
F: FnOnce(&T) -> Result<serde_json::Value, BridgeError>,
{
let result = unsafe { read_input(ptr, len) }.and_then(|raw| {
let input: T = serde_json::from_str(&raw)
.map_err(|e| BridgeError::invalid_argument(format!("invalid input JSON: {e}")))?;
let value = compute(&input)?;
serde_json::to_string(&value)
.map_err(|e| BridgeError::internal(format!("failed to serialize result: {e}")))
});
match result {
Ok(json) => hand_over(json),
Err(err) => error_result(&err),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn iztro_wasm_alloc(len: u32) -> *mut u8 {
let buf = vec![0u8; len as usize];
Box::leak(buf.into_boxed_slice()).as_mut_ptr()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn iztro_wasm_free(ptr: *mut u8, len: u32) {
if !ptr.is_null() {
unsafe {
drop(Box::from_raw(std::ptr::slice_from_raw_parts_mut(
ptr,
len as usize,
)));
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn iztro_wasm_by_solar(ptr: *const u8, len: u32) -> u64 {
unsafe { run(ptr, len, |input: &SolarChartInput| bridge::by_solar(input)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn iztro_wasm_by_lunar(ptr: *const u8, len: u32) -> u64 {
unsafe { run(ptr, len, |input: &LunarChartInput| bridge::by_lunar(input)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn iztro_wasm_horoscope(ptr: *const u8, len: u32) -> u64 {
unsafe { run(ptr, len, |input: &HoroscopeInput| bridge::horoscope(input)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn iztro_wasm_query(ptr: *const u8, len: u32) -> u64 {
unsafe {
run(ptr, len, |input: &QueryInput| {
bridge::query(input).map(|value| serde_json::json!({ "value": value }))
})
}
}