mirror of
https://github.com/fluencelabs/marine-rs-sdk-test
synced 2024-12-04 23:30:18 +00:00
some improvements
This commit is contained in:
parent
440c5992c1
commit
7b8d72e84c
@ -17,6 +17,7 @@
|
|||||||
mod item_fn;
|
mod item_fn;
|
||||||
mod item_foreign_mod;
|
mod item_foreign_mod;
|
||||||
mod item_record;
|
mod item_record;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use crate::fce_ast_types::FCEAst;
|
use crate::fce_ast_types::FCEAst;
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ use crate::ParsedType;
|
|||||||
use crate::fce_ast_types::FCEAst;
|
use crate::fce_ast_types::FCEAst;
|
||||||
use crate::fce_ast_types::AstFunctionItem;
|
use crate::fce_ast_types::AstFunctionItem;
|
||||||
use crate::fce_ast_types::AstFuncArgument;
|
use crate::fce_ast_types::AstFuncArgument;
|
||||||
use crate::parsed_type::passing_style_of;
|
|
||||||
use crate::syn_error;
|
use crate::syn_error;
|
||||||
|
|
||||||
use syn::Result;
|
use syn::Result;
|
||||||
@ -148,23 +147,10 @@ fn check_parsed_functions<'a>(
|
|||||||
/// Vec<Vec<&Vec<String>>> => true
|
/// Vec<Vec<&Vec<String>>> => true
|
||||||
/// &Vec<String> => false
|
/// &Vec<String> => false
|
||||||
fn contains_inner_ref(ty: &ParsedType) -> bool {
|
fn contains_inner_ref(ty: &ParsedType) -> bool {
|
||||||
fn contains_inner_ref_impl(ty: &ParsedType) -> bool {
|
use super::utils::contain_inner_ref;
|
||||||
use crate::parsed_type::PassingStyle;
|
|
||||||
|
|
||||||
match ty {
|
|
||||||
ParsedType::Vector(ty, passing_style) => match passing_style {
|
|
||||||
PassingStyle::ByValue => contains_inner_ref_impl(ty),
|
|
||||||
PassingStyle::ByRef | PassingStyle::ByMutRef => true,
|
|
||||||
},
|
|
||||||
_ => match passing_style_of(ty) {
|
|
||||||
PassingStyle::ByValue => false,
|
|
||||||
PassingStyle::ByRef | PassingStyle::ByMutRef => true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match ty {
|
match ty {
|
||||||
ParsedType::Vector(ty, _) => contains_inner_ref_impl(ty),
|
ParsedType::Vector(ty, _) => contain_inner_ref(ty),
|
||||||
// Structs are checked while parsing
|
// Structs are checked while parsing
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -28,65 +28,105 @@ const WASM_IMPORT_MODULE_DIRECTIVE_NAME: &str = "wasm_import_module";
|
|||||||
|
|
||||||
impl ParseMacroInput for syn::ItemForeignMod {
|
impl ParseMacroInput for syn::ItemForeignMod {
|
||||||
fn parse_macro_input(self) -> Result<FCEAst> {
|
fn parse_macro_input(self) -> Result<FCEAst> {
|
||||||
match &self.abi.name {
|
check_foreign_section(&self)?;
|
||||||
Some(name) if name.value() != "C" => {
|
|
||||||
return syn_error!(self.span(), "only 'C' abi is allowed")
|
let wasm_import_module: Option<String> = parse_wasm_import_module(&self);
|
||||||
}
|
let namespace = try_extract_namespace(wasm_import_module, &self)?;
|
||||||
_ => {}
|
|
||||||
|
let imports = extract_import_functions(&self)?;
|
||||||
|
check_imports(imports.iter().zip(self.items.iter().map(|i| i.span())))?;
|
||||||
|
|
||||||
|
let extern_mod_item = fce_ast_types::AstExternModItem {
|
||||||
|
namespace,
|
||||||
|
imports,
|
||||||
|
original: Some(self),
|
||||||
};
|
};
|
||||||
|
Ok(FCEAst::ExternMod(extern_mod_item))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let self_span = self.span();
|
fn check_foreign_section(foreign_mod: &syn::ItemForeignMod) -> Result<()> {
|
||||||
|
match &foreign_mod.abi.name {
|
||||||
|
Some(name) if name.value() != "C" => {
|
||||||
|
syn_error!(foreign_mod.span(), "only 'C' abi is allowed")
|
||||||
|
}
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let imports = self
|
/// Tries to find and parse wasm module name from
|
||||||
.items
|
/// #[link(wasm_import_module = "host")]
|
||||||
.iter()
|
fn parse_wasm_import_module(foreign_mod: &syn::ItemForeignMod) -> Option<String> {
|
||||||
.cloned()
|
foreign_mod
|
||||||
.map(parse_raw_foreign_item)
|
.attrs
|
||||||
.collect::<Result<_>>()?;
|
.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)
|
||||||
|
})
|
||||||
|
.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()
|
||||||
|
}
|
||||||
|
|
||||||
// try to find and parse wasm module name from
|
fn try_extract_namespace(
|
||||||
// #[link(wasm_import_module = "host")]
|
attr: Option<String>,
|
||||||
let wasm_import_module: Option<String> = self
|
foreign_mod: &syn::ItemForeignMod,
|
||||||
.attrs
|
) -> Result<String> {
|
||||||
.iter()
|
match attr {
|
||||||
.filter_map(|attr| attr.parse_meta().ok())
|
Some(namespace) if namespace.is_empty() => syn_error!(
|
||||||
.filter(|meta| meta.path().is_ident(LINK_DIRECTIVE_NAME))
|
foreign_mod.span(),
|
||||||
.filter_map(|meta| {
|
"import module name should be defined by 'wasm_import_module' directive"
|
||||||
let pair = match meta {
|
),
|
||||||
syn::Meta::List(mut meta_list) if meta_list.nested.len() == 1 => {
|
Some(namespace) => Ok(namespace),
|
||||||
meta_list.nested.pop().unwrap()
|
None => syn_error!(
|
||||||
}
|
foreign_mod.span(),
|
||||||
_ => return None,
|
"import module name should be defined by 'wasm_import_module' directive"
|
||||||
};
|
),
|
||||||
Some(pair.into_tuple().0)
|
}
|
||||||
})
|
}
|
||||||
.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();
|
|
||||||
|
|
||||||
match wasm_import_module {
|
fn extract_import_functions(
|
||||||
Some(namespace) if namespace.is_empty() => syn_error!(
|
foreign_mod: &syn::ItemForeignMod,
|
||||||
self_span,
|
) -> Result<Vec<fce_ast_types::AstExternFnItem>> {
|
||||||
"import module name should be defined by 'wasm_import_module' directive"
|
foreign_mod
|
||||||
),
|
.items
|
||||||
Some(namespace) => {
|
.iter()
|
||||||
let extern_mod_item = fce_ast_types::AstExternModItem {
|
.cloned()
|
||||||
namespace,
|
.map(parse_raw_foreign_item)
|
||||||
imports,
|
.collect::<Result<_>>()
|
||||||
original: Some(self),
|
}
|
||||||
};
|
|
||||||
Ok(FCEAst::ExternMod(extern_mod_item))
|
/// This function checks whether these imports contains inner references. In this case glue
|
||||||
|
/// code couldn't be generated.
|
||||||
|
fn check_imports<'i>(
|
||||||
|
extern_fns: impl ExactSizeIterator<Item = (&'i fce_ast_types::AstExternFnItem, proc_macro2::Span)>,
|
||||||
|
) -> Result<()> {
|
||||||
|
use super::utils::contain_inner_ref;
|
||||||
|
|
||||||
|
for (extern_fn, span) in extern_fns {
|
||||||
|
if let Some(output_type) = &extern_fn.signature.output_type {
|
||||||
|
if contain_inner_ref(output_type) {
|
||||||
|
return crate::syn_error!(
|
||||||
|
span,
|
||||||
|
"import function can't return a value with references"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
None => syn_error!(
|
|
||||||
self_span,
|
|
||||||
"import module name should be defined by 'wasm_import_module' directive"
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_raw_foreign_item(raw_item: syn::ForeignItem) -> Result<fce_ast_types::AstExternFnItem> {
|
fn parse_raw_foreign_item(raw_item: syn::ForeignItem) -> Result<fce_ast_types::AstExternFnItem> {
|
||||||
|
33
crates/wit/src/parse_macro_input/utils.rs
Normal file
33
crates/wit/src/parse_macro_input/utils.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::ParsedType;
|
||||||
|
use crate::parsed_type::PassingStyle;
|
||||||
|
use crate::parsed_type::passing_style_of;
|
||||||
|
|
||||||
|
/// Checks whether a type contains a reference in one of types.
|
||||||
|
pub(super) fn contain_inner_ref(ty: &ParsedType) -> bool {
|
||||||
|
let passing_style = passing_style_of(ty);
|
||||||
|
match passing_style {
|
||||||
|
PassingStyle::ByValue => {}
|
||||||
|
PassingStyle::ByRef | PassingStyle::ByMutRef => return true,
|
||||||
|
};
|
||||||
|
|
||||||
|
match ty {
|
||||||
|
ParsedType::Vector(ty, _) => contain_inner_ref(ty),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
@ -57,7 +57,7 @@ pub enum ParsedType {
|
|||||||
Record(String, PassingStyle), // short type name
|
Record(String, PassingStyle), // short type name
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum PassingStyle {
|
pub enum PassingStyle {
|
||||||
ByValue,
|
ByValue,
|
||||||
ByRef,
|
ByRef,
|
||||||
|
@ -116,11 +116,14 @@ fn generate_epilog(ty: &Option<ParsedType>) -> proc_macro2::TokenStream {
|
|||||||
fluence::internal::set_result_size(result.len() as _);
|
fluence::internal::set_result_size(result.len() as _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ParsedType::Vector(ty, _)) => {
|
Some(ParsedType::Vector(ty, passing_style)) => {
|
||||||
let generated_serializer_name = "__fce_generated_vec_serializer";
|
let generated_serializer_name = "__fce_generated_vec_serializer";
|
||||||
let generated_serializer_ident = new_ident!(generated_serializer_name);
|
let generated_serializer_ident = new_ident!(generated_serializer_name);
|
||||||
let vector_serializer =
|
let vector_serializer = super::vector_utils::generate_vector_serializer(
|
||||||
super::vector_utils::generate_vector_serializer(ty, generated_serializer_name);
|
ty,
|
||||||
|
*passing_style,
|
||||||
|
generated_serializer_name,
|
||||||
|
);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#vector_serializer
|
#vector_serializer
|
||||||
|
@ -81,11 +81,11 @@ impl ForeignModPrologGlueCodeGenerator for Vec<AstFuncArgument> {
|
|||||||
arg_transforms.extend(quote::quote! { let mut #arg_ident = std::mem::ManuallyDrop::new(#arg_ident); });
|
arg_transforms.extend(quote::quote! { let mut #arg_ident = std::mem::ManuallyDrop::new(#arg_ident); });
|
||||||
arg_drops.extend(quote::quote! { std::mem::ManuallyDrop::drop(&mut #arg_ident); });
|
arg_drops.extend(quote::quote! { std::mem::ManuallyDrop::drop(&mut #arg_ident); });
|
||||||
},
|
},
|
||||||
ParsedType::Vector(ty, _) => {
|
ParsedType::Vector(ty, passing_style) => {
|
||||||
let generated_serializer_name = format!("__fce_generated_vec_serializer_{}", arg_name).replace("&<>", "_");
|
let generated_serializer_name = format!("__fce_generated_vec_serializer_{}", arg_name).replace("&<>", "_");
|
||||||
|
|
||||||
let generated_serializer_ident = new_ident!(generated_serializer_name);
|
let generated_serializer_ident = new_ident!(generated_serializer_name);
|
||||||
let vector_serializer = super::vector_utils::generate_vector_serializer(ty, &generated_serializer_name);
|
let vector_serializer = super::vector_utils::generate_vector_serializer(ty, *passing_style, &generated_serializer_name);
|
||||||
|
|
||||||
let arg_transform = quote::quote! {
|
let arg_transform = quote::quote! {
|
||||||
#vector_serializer
|
#vector_serializer
|
||||||
|
@ -15,21 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use super::ParsedType;
|
use super::ParsedType;
|
||||||
|
use super::PassingStyle;
|
||||||
|
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
pub(crate) fn generate_vector_serializer(
|
pub(crate) fn generate_vector_serializer(
|
||||||
value_ty: &ParsedType,
|
value_ty: &ParsedType,
|
||||||
arg_name: &str,
|
vec_passing_style: PassingStyle,
|
||||||
) -> proc_macro2::TokenStream {
|
|
||||||
let serializer_func = generate_vector_serializer_impl(value_ty, arg_name);
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#serializer_func
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_vector_serializer_impl(
|
|
||||||
value_ty: &ParsedType,
|
|
||||||
arg_name: &str,
|
arg_name: &str,
|
||||||
) -> proc_macro2::TokenStream {
|
) -> proc_macro2::TokenStream {
|
||||||
let values_serializer = match value_ty {
|
let values_serializer = match value_ty {
|
||||||
@ -90,12 +82,13 @@ fn generate_vector_serializer_impl(
|
|||||||
(result.as_ptr() as _, (4 * result.len()) as _)
|
(result.as_ptr() as _, (4 * result.len()) as _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParsedType::Vector(ty, _) => {
|
ParsedType::Vector(ty, passing_style) => {
|
||||||
let serializer_name = format!("{}_{}", arg_name, ty)
|
let serializer_name = format!("{}_{}", arg_name, ty)
|
||||||
.replace("<", "_")
|
.replace("<", "_")
|
||||||
.replace(">", "_")
|
.replace(">", "_")
|
||||||
.replace("&", "_");
|
.replace("&", "_");
|
||||||
let inner_vector_serializer = generate_vector_serializer(&*ty, &serializer_name);
|
let inner_vector_serializer =
|
||||||
|
generate_vector_serializer(&*ty, *passing_style, &serializer_name);
|
||||||
let serializer_ident = crate::new_ident!(serializer_name);
|
let serializer_ident = crate::new_ident!(serializer_name);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
@ -128,7 +121,7 @@ fn generate_vector_serializer_impl(
|
|||||||
let arg = crate::new_ident!(arg_name);
|
let arg = crate::new_ident!(arg_name);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
unsafe fn #arg(arg: Vec<#value_ty>) -> (u32, u32) {
|
unsafe fn #arg(arg: #vec_passing_style Vec<#value_ty>) -> (u32, u32) {
|
||||||
#values_serializer
|
#values_serializer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
|
|||||||
std::mem::forget(#field_ident);
|
std::mem::forget(#field_ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParsedType::Vector(ty, _) => {
|
ParsedType::Vector(ty, passing_style) => {
|
||||||
let generated_serializer_name = format!(
|
let generated_serializer_name = format!(
|
||||||
"__fce_generated_vec_serializer_{}_{}",
|
"__fce_generated_vec_serializer_{}_{}",
|
||||||
field.name.as_ref().unwrap(),
|
field.name.as_ref().unwrap(),
|
||||||
@ -54,6 +54,7 @@ impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
|
|||||||
let generated_serializer_ident = new_ident!(generated_serializer_name);
|
let generated_serializer_ident = new_ident!(generated_serializer_name);
|
||||||
let vector_serializer = crate::parsed_type::generate_vector_serializer(
|
let vector_serializer = crate::parsed_type::generate_vector_serializer(
|
||||||
ty,
|
ty,
|
||||||
|
*passing_style,
|
||||||
&generated_serializer_name,
|
&generated_serializer_name,
|
||||||
);
|
);
|
||||||
let serialized_field_ident = new_ident!(format!("serialized_arg_{}", id));
|
let serialized_field_ident = new_ident!(format!("serialized_arg_{}", id));
|
||||||
|
27
fluence/tests/import_functions/arrays_out_inner_refs.rs
Normal file
27
fluence/tests/import_functions/arrays_out_inner_refs.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#![allow(improper_ctypes)]
|
||||||
|
|
||||||
|
use fluence::fce;
|
||||||
|
|
||||||
|
pub fn main() {}
|
||||||
|
|
||||||
|
#[fce]
|
||||||
|
#[link(wasm_import_module = "arrays_passing_effector")]
|
||||||
|
extern "C" {
|
||||||
|
#[fce]
|
||||||
|
pub fn func_1() -> &String;
|
||||||
|
|
||||||
|
#[fce]
|
||||||
|
pub fn func_2() -> &Vec<Vec<Vec<Vec<u8>>>>;
|
||||||
|
|
||||||
|
#[fce]
|
||||||
|
pub fn func_3() -> Vec<&Vec<Vec<Vec<u8>>>>;
|
||||||
|
|
||||||
|
#[fce]
|
||||||
|
pub fn func_4() -> Vec<Vec<&Vec<Vec<u8>>>>;
|
||||||
|
|
||||||
|
#[fce]
|
||||||
|
pub fn func_5() -> Vec<Vec<Vec<&Vec<u8>>>>;
|
||||||
|
|
||||||
|
#[fce]
|
||||||
|
pub fn func_6() -> Vec<Vec<Vec<Vec<&u8>>>>;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
error: import function can't return a value with references
|
||||||
|
--> $DIR/arrays_out_inner_refs.rs:10:5
|
||||||
|
|
|
||||||
|
10 | / #[fce]
|
||||||
|
11 | | pub fn func_1() -> &String;
|
||||||
|
| |_______________________________^
|
@ -8,6 +8,7 @@ fn test() {
|
|||||||
tests.pass("tests/export_functions/ref_basic_types.rs");
|
tests.pass("tests/export_functions/ref_basic_types.rs");
|
||||||
tests.compile_fail("tests/export_functions/improper_types.rs");
|
tests.compile_fail("tests/export_functions/improper_types.rs");
|
||||||
|
|
||||||
|
tests.compile_fail("tests/import_functions/arrays_out_inner_refs.rs");
|
||||||
tests.pass("tests/import_functions/arrays.rs");
|
tests.pass("tests/import_functions/arrays.rs");
|
||||||
tests.pass("tests/import_functions/ref_arrays.rs");
|
tests.pass("tests/import_functions/ref_arrays.rs");
|
||||||
tests.pass("tests/import_functions/basic_types.rs");
|
tests.pass("tests/import_functions/basic_types.rs");
|
||||||
|
Loading…
Reference in New Issue
Block a user