#[macro_export]
macro_rules! export_wasm_extension {
($extension_type:ty) => {
use std::sync::OnceLock;
use torigen_mounter::core::wasm::{
ExtensionMethods, WasmExtension, WasmExtensionProvider, WasmExtensionWrapper,
};
static EXTENSION: OnceLock<WasmExtensionWrapper<$extension_type>> = OnceLock::new();
fn get_extension() -> &'static WasmExtensionWrapper<$extension_type> {
EXTENSION.get_or_init(|| WasmExtensionWrapper::new(<$extension_type>::new()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn extension_call(
method_name_ptr: *const u8,
method_name_len: usize,
args_ptr: *const u8,
args_len: usize,
result_ptr: *mut u8,
result_len: *mut usize,
) -> i32 {
let method_name = match unsafe {
std::str::from_utf8(std::slice::from_raw_parts(method_name_ptr, method_name_len))
} {
Ok(s) => s,
Err(_) => return -1,
};
let args = if args_len > 0 {
match unsafe { std::str::from_utf8(std::slice::from_raw_parts(args_ptr, args_len)) }
{
Ok(s) => s,
Err(_) => return -1,
}
} else {
""
};
let method = match ExtensionMethods::from_str(method_name) {
Some(m) => m,
None => return -1,
};
let result = match method {
ExtensionMethods::GetSourceInfo => get_extension().get_source_info(),
ExtensionMethods::GetMetadata => get_extension().get_metadata(),
ExtensionMethods::GetHomepageRequest => get_extension().get_homepage_request(),
ExtensionMethods::ProcessHomepageRes => get_extension().process_homepage_res(args),
ExtensionMethods::GetViewmoreRequest => {
let parsed: Result<serde_json::Value, _> = serde_json::from_str(args);
match parsed {
Ok(json) => {
let section_id = json["section_id"].as_str().unwrap_or("");
let page = json["page"].as_u64().unwrap_or(1) as u32;
get_extension().get_viewmore_request(section_id, page)
}
Err(_) => return -1,
}
}
ExtensionMethods::ProcessViewmoreRes => get_extension().process_viewmore_res(args),
ExtensionMethods::GetSearchRequest => get_extension().get_search_request(args),
ExtensionMethods::ProcessSearchRes => get_extension().process_search_res(args),
ExtensionMethods::GetSearchTagsRequest => get_extension().get_search_tags_request(),
ExtensionMethods::ProcessSearchTagsRes => {
get_extension().process_search_tags_res(args)
}
ExtensionMethods::GetMangaRequest => get_extension().get_manga_request(args),
ExtensionMethods::ProcessMangaRes => get_extension().process_manga_res(args),
ExtensionMethods::GetChaptersRequest => get_extension().get_chapters_request(args),
ExtensionMethods::ProcessChaptersRes => get_extension().process_chapters_res(args),
ExtensionMethods::GetChapterDetailsRequest => {
let parsed: Result<serde_json::Value, _> = serde_json::from_str(args);
match parsed {
Ok(json) => {
let manga_id = json["manga_id"].as_str().unwrap_or("");
let chapter_id = json["chapter_id"].as_str().unwrap_or("");
get_extension().get_chapter_details_request(manga_id, chapter_id)
}
Err(_) => return -1,
}
}
ExtensionMethods::ProcessChapterDetailsRes => {
get_extension().process_chapter_details_res(args)
}
};
let result_bytes = result.as_bytes();
if result_bytes.len() <= unsafe { *result_len } {
unsafe {
std::ptr::copy_nonoverlapping(
result_bytes.as_ptr(),
result_ptr,
result_bytes.len(),
);
*result_len = result_bytes.len();
}
0
} else {
unsafe {
*result_len = result_bytes.len();
}
1
}
}
};
}