feat!: introduce host import API versions (#154)

* introduce __marine_host_api_v1

* fix warnings

* updatre comment

* fix clippy warnings
This commit is contained in:
Valery Antopol 2024-02-08 16:20:14 +04:00 committed by GitHub
parent 911a08fffe
commit eaf9512cf1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 67 additions and 41 deletions

View File

@ -136,7 +136,7 @@ pub fn get_call_parameters() -> CallParameters {
}
#[cfg(all(feature = "marine-abi", target_arch = "wasm32"))]
#[link(wasm_import_module = "host")]
#[link(wasm_import_module = "__marine_host_api_v1")]
#[allow(improper_ctypes)]
extern "C" {
// returns serialized current call parameters

View File

@ -238,10 +238,11 @@ pub fn log_utf8_string(level: i32, target: i32, msg_ptr: i32, msg_size: i32) {
println!("[{}] {} {}", level, target, msg);
}
#[allow(unused_doc_comments)]
/// TODO: mark `log_utf8_string_impl` as #[wasm_bindgen], so it is polyfilled by bindgen
/// log_utf8_string should be provided directly by a host.
#[cfg(all(feature = "marine-abi", target_arch = "wasm32"))]
#[link(wasm_import_module = "host")]
#[link(wasm_import_module = "__marine_host_api_v1")]
extern "C" {
// Writes a byte string of size bytes that starts from ptr to a logger
#[link_name = "log_utf8_string"]

View File

@ -49,3 +49,5 @@ pub use token_stream_generator::GENERATED_GLOBAL_PREFIX;
pub use wasm_type::RustType;
pub const GENERATED_SECTION_PREFIX_FCE: &str = "__fce_generated_section__";
pub const MARINE_HOST_API_NAMESPACE_PREFIX: &str = "__marine_host_api_v";
pub const MARINE_HOST_API_VERSION: u32 = 1;

View File

@ -22,15 +22,16 @@ use crate::syn_error;
use syn::Result;
use syn::spanned::Spanned;
const LINK_DIRECTIVE_NAME: &str = "link";
const LINK_NAME_DIRECTIVE_NAME: &str = "link_name";
const WASM_IMPORT_MODULE_DIRECTIVE_NAME: &str = "wasm_import_module";
const HOST_IMPORT_DIRECTIVE_NAME: &str = "host_import";
const MODULE_IMPORT_DIRECTIVE_NAME: &str = "module_import";
const HOST_IMPORT_NAMESPACE: &str = "__marine_host_api_v1";
impl ParseMacroInput for syn::ItemForeignMod {
fn parse_macro_input(self) -> Result<MarineAst> {
check_foreign_section(&self)?;
let wasm_import_module: Option<String> = parse_wasm_import_module(&self);
let wasm_import_module = parse_wasm_import_module(&self);
let namespace = try_extract_namespace(wasm_import_module, &self)?;
let imports = extract_import_functions(&self)?;
@ -51,46 +52,68 @@ fn check_foreign_section(foreign_mod: &syn::ItemForeignMod) -> Result<()> {
}
/// Tries to find and parse wasm module name from
/// #[link(wasm_import_module = "host")]
fn parse_wasm_import_module(foreign_mod: &syn::ItemForeignMod) -> Option<String> {
/// #[module_import("module_name")] or #[host_import]
fn parse_wasm_import_module(foreign_mod: &syn::ItemForeignMod) -> Vec<String> {
foreign_mod
.attrs
.iter()
.filter_map(|attr| attr.parse_meta().ok())
.filter(|meta| meta.path().is_ident(LINK_DIRECTIVE_NAME))
.filter_map(|meta| {
let pair = match meta {
syn::Meta::List(mut meta_list) if meta_list.nested.len() == 1 => {
meta_list.nested.pop().unwrap()
}
_ => return None,
};
Some(pair.into_tuple().0)
if meta.path().is_ident(HOST_IMPORT_DIRECTIVE_NAME) {
Some(HOST_IMPORT_NAMESPACE.to_string())
} else if meta.path().is_ident(MODULE_IMPORT_DIRECTIVE_NAME) {
parse_module_import_directive(meta)
} else {
None
}
})
.filter_map(|nested| match nested {
syn::NestedMeta::Meta(meta) => Some(meta),
_ => None,
})
.filter(|meta| meta.path().is_ident(WASM_IMPORT_MODULE_DIRECTIVE_NAME))
.map(extract_value)
.collect()
}
fn parse_module_import_directive(meta: syn::Meta) -> Option<String> {
let nested_meta = match meta {
syn::Meta::List(mut meta_list) if meta_list.nested.len() == 1 => {
Some(meta_list.nested.pop().unwrap())
}
_ => None,
}?;
match nested_meta.value() {
syn::NestedMeta::Lit(syn::Lit::Str(lit)) => Some(lit.value()),
_ => None,
}
}
fn try_extract_namespace(
attr: Option<String>,
mut attr: Vec<String>,
foreign_mod: &syn::ItemForeignMod,
) -> Result<String> {
match attr {
Some(namespace) if namespace.is_empty() => syn_error!(
if attr.is_empty() {
return syn_error!(
foreign_mod.span(),
"import module name should be defined by 'wasm_import_module' directive"
),
Some(namespace) => Ok(namespace),
None => syn_error!(
foreign_mod.span(),
"import module name should be defined by 'wasm_import_module' directive"
),
"import module name should be defined by either '#[host_import]' or '#[module_import(\"module_name\")]' attributes"
);
}
if attr.len() > 1 {
return syn_error!(
foreign_mod.span(),
"only one of '#[host_import]' or '#[module_import(\"module_name\")]' attributes is allowed"
);
}
let namespace = attr
.pop()
.expect("length of attribute vec should be checked before");
if namespace.is_empty() {
return syn_error!(
foreign_mod.span(),
"#[module_import(\"module_name\")] attribute should have a non-empty module name"
);
}
Ok(namespace)
}
fn extract_import_functions(

View File

@ -1,4 +1,4 @@
#[link(wasm_import_module = "test")]
#[module_import("test")]
extern "C" {
pub fn inner_arrays_1(arg: Vec<Vec<Vec<Vec<u8>>>>) -> Vec<Vec<Vec<Vec<u8>>>>;
}

View File

@ -1,4 +1,4 @@
#[link(wasm_import_module = "test")]
#[module_import("test")]
extern "C" {
pub fn all_types(
arg_0: i8,

View File

@ -12,7 +12,7 @@ pub struct TestRecord {
}
#[marine]
#[link(wasm_import_module = "arrays_passing_effector")]
#[module_import("arrays_passing_effector")]
extern "C" {
pub fn inner_arrays_1(arg: Vec<Vec<Vec<Vec<u8>>>>) -> Vec<Vec<Vec<Vec<u8>>>>;

View File

@ -5,7 +5,7 @@ use marine_rs_sdk::marine;
pub fn main() {}
#[marine]
#[link(wasm_import_module = "arrays_passing_effector")]
#[module_import("arrays_passing_effector")]
extern "C" {
#[marine]
pub fn func_1() -> &String;

View File

@ -5,7 +5,7 @@ use marine_rs_sdk::marine;
fn main() {}
#[marine]
#[link(wasm_import_module = "arguments_passing_effector")]
#[module_import("arrays_passing_effector")]
extern "C" {
pub fn all_ref_types(
arg_0: &i8,

View File

@ -5,7 +5,7 @@ use marine_rs_sdk::marine;
fn main() {}
#[marine]
#[link(wasm_import_module = "arguments_passing_effector")]
#[module_import("arguments_passing_effector")]
extern "C" {
pub fn all_types(
arg_0: i8,

View File

@ -5,7 +5,7 @@ use marine_rs_sdk::marine;
pub fn main() {}
#[marine]
#[link(wasm_import_module = "arguments_passing_effector")]
#[module_import("arrays_passing_effector")]
extern "C" {
#[marine]
fn test(_arg_1: Box<i32>);

View File

@ -12,7 +12,7 @@ pub struct TestRecord {
}
#[marine]
#[link(wasm_import_module = "arrays_passing_effector")]
#[module_import("arrays_passing_effector")]
extern "C" {
pub fn inner_arrays_1(arg: &Vec<Vec<Vec<Vec<u8>>>>) -> Vec<Vec<Vec<Vec<u8>>>>;
pub fn inner_arrays_2(arg: &Vec<&Vec<Vec<Vec<u8>>>>) -> Vec<Vec<Vec<Vec<u8>>>>;

View File

@ -5,7 +5,7 @@ use marine_rs_sdk::marine;
fn main() {}
#[marine]
#[link(wasm_import_module = "arguments_passing_effector")]
#[module_import("arrays_passing_effector")]
extern "C" {
pub fn all_types(
arg_0: &i8,

View File

@ -14,7 +14,7 @@ struct StructWithPrivateFields {
fn export_func(_field: StructWithPrivateFields) { }
#[marine]
#[link(wasm_import_module = "record_module")]
#[module_import("record_module")]
extern "C" {
fn import_func(arg: &StructWithPrivateFields) -> StructWithPrivateFields;
}