mirror of
https://github.com/fluencelabs/marine-rs-sdk-test
synced 2024-12-04 15:20:18 +00:00
support records
This commit is contained in:
parent
79a5896015
commit
e589d52c72
@ -34,8 +34,8 @@ pub struct AstFunctionSignature {
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AstRecordField {
|
||||
// fields of tuple structs haven't got name
|
||||
pub field_name: Option<String>,
|
||||
pub field_type: ParsedType,
|
||||
pub name: Option<String>,
|
||||
pub ty: ParsedType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
|
@ -40,7 +40,7 @@ mod wasm_type;
|
||||
pub use fce_ast_types::*;
|
||||
pub use fce_macro_impl::fce;
|
||||
pub use parsed_type::ParsedType;
|
||||
pub use token_stream_generator::GENERATED_FUNC_PREFIX;
|
||||
pub use token_stream_generator::GENERATED_WRAPPER_FUNC_PREFIX;
|
||||
pub use token_stream_generator::GENERATED_SECTION_PREFIX;
|
||||
pub use token_stream_generator::GENERATED_GLOBAL_PREFIX;
|
||||
pub use wasm_type::WasmType;
|
||||
|
@ -40,8 +40,8 @@ impl ParseMacroInput for syn::ItemStruct {
|
||||
let field_name = field.ident.as_ref().map(|ident| ident.to_string());
|
||||
let field_type = ParsedType::from_type(&field.ty)?;
|
||||
Ok(AstRecordField {
|
||||
field_name,
|
||||
field_type,
|
||||
name: field_name,
|
||||
ty: field_type,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
@ -52,6 +52,7 @@ pub enum ParsedType {
|
||||
|
||||
impl ParsedType {
|
||||
pub fn from_type(input_type: &syn::Type) -> syn::Result<Self> {
|
||||
use quote::ToTokens;
|
||||
// parses generic param T in Vec<T> to string representation
|
||||
fn parse_vec_bracket(args: &syn::PathArguments) -> syn::Result<String> {
|
||||
// checks that T is angle bracketed
|
||||
@ -121,12 +122,7 @@ impl ParsedType {
|
||||
// argument can be given in full path form: ::std::string::String
|
||||
// that why the last one used
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
path.span(),
|
||||
"The invocation handler should have a non-empty input argument type",
|
||||
)
|
||||
})?;
|
||||
.ok_or_else(|| Error::new(path.span(), "Type should be specified"))?;
|
||||
|
||||
match type_segment.ident.to_string().as_str() {
|
||||
"i8" => Ok(ParsedType::I8),
|
||||
@ -151,10 +147,11 @@ impl ParsedType {
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
type_name => Err(Error::new(
|
||||
_ if !type_segment.arguments.is_empty() => Err(Error::new(
|
||||
type_segment.span(),
|
||||
format!("{} is unsupported", type_name),
|
||||
"type with lifetimes or generics aren't allowed".to_string(),
|
||||
)),
|
||||
_ => Ok(ParsedType::Record(path.into_token_stream().to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::new_ident;
|
||||
use super::ParsedType;
|
||||
use crate::new_ident;
|
||||
use crate::token_stream_generator::GENERATED_RECORD_SERIALIZER_PREFIX;
|
||||
|
||||
use quote::quote;
|
||||
|
||||
@ -96,6 +97,14 @@ fn generate_epilog(ty: &Option<ParsedType>) -> proc_macro2::TokenStream {
|
||||
Some(ty) if !ty.is_integral_type() => quote! {
|
||||
return result as _;
|
||||
},
|
||||
Some(ParsedType::Record(record_name)) => {
|
||||
let serializer =
|
||||
crate::new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + record_name);
|
||||
quote! {
|
||||
let result_ptr = #serializer(result);
|
||||
fluence::internal::set_result_ptr(result_ptr as _);
|
||||
}
|
||||
}
|
||||
Some(ty) if ty.is_integral_type() => quote! {
|
||||
fluence::internal::set_result_ptr(result.as_ptr() as _);
|
||||
fluence::internal::set_result_size(result.len() as _);
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
use super::ParsedType;
|
||||
use super::FnArgGlueCodeGenerator;
|
||||
use crate::token_stream_generator::GENERATED_RECORD_DESERIALIZER_PREFIX;
|
||||
use crate::new_ident;
|
||||
use crate::wasm_type::WasmType;
|
||||
|
||||
@ -104,9 +105,14 @@ fn generate_type_prolog(
|
||||
ParsedType::ByteVector => quote! {
|
||||
let #generated_arg_id = Vec::from_raw_parts(#ptr as _, #size as _, #size as _);
|
||||
},
|
||||
ParsedType::Record(record_name) => quote! {
|
||||
let #generated_arg_id = __fce_generated_converter_#record_name(#ptr, #size);
|
||||
},
|
||||
ParsedType::Record(record_name) => {
|
||||
let deserializer = crate::new_ident!(
|
||||
GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + record_name
|
||||
);
|
||||
quote! {
|
||||
let #generated_arg_id = #deserializer(#ptr, #size);
|
||||
}
|
||||
}
|
||||
_ => panic!(
|
||||
"perhaps new type's been added to ParsedType, and this match became incomplete"
|
||||
),
|
||||
|
@ -22,7 +22,9 @@ use crate::fce_ast_types::FCEAst;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
pub const GENERATED_FUNC_PREFIX: &str = "__fce_generated_func_";
|
||||
pub const GENERATED_WRAPPER_FUNC_PREFIX: &str = "__fce_generated_wrapper_func_";
|
||||
pub const GENERATED_RECORD_SERIALIZER_PREFIX: &str = "__fce_generated_record_serializer_";
|
||||
pub const GENERATED_RECORD_DESERIALIZER_PREFIX: &str = "__fce_generated_record_deserializer_";
|
||||
pub const GENERATED_SECTION_PREFIX: &str = "__fce_generated_section__";
|
||||
pub const GENERATED_GLOBAL_PREFIX: &str = "__fce_generated_static_global_";
|
||||
|
||||
|
@ -37,7 +37,7 @@ impl quote::ToTokens for fce_ast_types::AstFunctionItem {
|
||||
);
|
||||
|
||||
let signature = &self.signature;
|
||||
let func_name = new_ident!(GENERATED_FUNC_PREFIX.to_string() + &signature.name);
|
||||
let func_name = new_ident!(GENERATED_WRAPPER_FUNC_PREFIX.to_string() + &signature.name);
|
||||
let original_func_ident = new_ident!(signature.name);
|
||||
let export_func_name = &signature.name;
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use super::GENERATED_FUNC_PREFIX;
|
||||
use super::GENERATED_WRAPPER_FUNC_PREFIX;
|
||||
use crate::fce_ast_types;
|
||||
use crate::new_ident;
|
||||
|
||||
@ -89,7 +89,7 @@ fn generate_extern_section_items(extern_item: &fce_ast_types::AstExternModItem)
|
||||
}
|
||||
|
||||
fn generate_import_name(import_name: &str) -> syn::Ident {
|
||||
crate::new_ident!(format!("{}_{}", GENERATED_FUNC_PREFIX, import_name))
|
||||
crate::new_ident!(format!("{}_{}", GENERATED_WRAPPER_FUNC_PREFIX, import_name))
|
||||
}
|
||||
|
||||
fn generate_wrapper_functions(extern_item: &fce_ast_types::AstExternModItem) -> TokenStream {
|
||||
|
@ -14,7 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use super::GENERATED_RECORD_SERIALIZER_PREFIX;
|
||||
use super::GENERATED_RECORD_DESERIALIZER_PREFIX;
|
||||
|
||||
use crate::new_ident;
|
||||
use crate::fce_ast_types;
|
||||
use crate::ParsedType;
|
||||
|
||||
impl quote::ToTokens for fce_ast_types::AstRecordItem {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
@ -29,9 +34,16 @@ impl quote::ToTokens for fce_ast_types::AstRecordItem {
|
||||
section_name
|
||||
);
|
||||
|
||||
let serializer = generate_serializer(self);
|
||||
let deserializer = generate_deserializer(self);
|
||||
|
||||
let glue_code = quote::quote! {
|
||||
#original
|
||||
|
||||
#serializer
|
||||
|
||||
#deserializer
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[doc(hidden)]
|
||||
#[allow(clippy::all)]
|
||||
@ -42,3 +54,210 @@ impl quote::ToTokens for fce_ast_types::AstRecordItem {
|
||||
tokens.extend(glue_code);
|
||||
}
|
||||
}
|
||||
|
||||
fn field_ident(field: &fce_ast_types::AstRecordField, id: usize) -> proc_macro2::TokenStream {
|
||||
match &field.name {
|
||||
Some(name) => {
|
||||
let name = new_ident!(name);
|
||||
quote::quote! { record.#name }
|
||||
}
|
||||
None => {
|
||||
let id = new_ident!(format!("{}", id));
|
||||
quote::quote! { record.#id }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_serializer(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream {
|
||||
let serializer_fn_name =
|
||||
new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + &record.name);
|
||||
let ty = new_ident!(record.name);
|
||||
|
||||
let mut serializer = proc_macro2::TokenStream::new();
|
||||
for (id, field) in record.fields.iter().enumerate() {
|
||||
let field_ident = field_ident(field, id);
|
||||
|
||||
let field_serialization = match &field.ty {
|
||||
ParsedType::F64 => {
|
||||
quote::quote! {
|
||||
raw_record.push(#field_ident.to_bits());
|
||||
}
|
||||
}
|
||||
ParsedType::Utf8String | ParsedType::ByteVector => {
|
||||
quote::quote! {
|
||||
raw_record.push(#field_ident.as_ptr() as _);
|
||||
raw_record.push(#field_ident.len() as _);
|
||||
}
|
||||
}
|
||||
ParsedType::Record(record_name) => {
|
||||
let serializer_name =
|
||||
new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + record_name);
|
||||
quote::quote! {
|
||||
raw_record.push(#serializer_name(#field_ident) as _);
|
||||
}
|
||||
}
|
||||
_ => quote::quote! {
|
||||
raw_record.push(#field_ident as u64);
|
||||
},
|
||||
};
|
||||
|
||||
serializer.extend(field_serialization);
|
||||
}
|
||||
|
||||
quote::quote! {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[doc(hidden)]
|
||||
#[allow(clippy::all)]
|
||||
pub(crate) fn #serializer_fn_name(record: #ty) -> i32 {
|
||||
let mut raw_record = Vec::new();
|
||||
|
||||
#serializer
|
||||
|
||||
let raw_record_ptr = raw_record.as_ptr();
|
||||
std::mem::forget(raw_record);
|
||||
|
||||
raw_record_ptr as _
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_deserializer(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream {
|
||||
let ret_type = new_ident!(record.name);
|
||||
let deserializer_fn_name =
|
||||
new_ident!(GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + &record.name);
|
||||
|
||||
let mut field_values = Vec::with_capacity(record.fields.len());
|
||||
let mut deserializer = proc_macro2::TokenStream::new();
|
||||
let mut value_id: usize = 0;
|
||||
|
||||
for (id, ast_field) in record.fields.iter().enumerate() {
|
||||
let field = new_ident!(format!("field_{}", id));
|
||||
let field_d = match &ast_field.ty {
|
||||
ParsedType::Boolean => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as bool;
|
||||
}
|
||||
}
|
||||
ParsedType::I8 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as i8;
|
||||
}
|
||||
}
|
||||
ParsedType::I16 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as i16;
|
||||
}
|
||||
}
|
||||
ParsedType::I32 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as i32;
|
||||
}
|
||||
}
|
||||
ParsedType::I64 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as i64;
|
||||
}
|
||||
}
|
||||
ParsedType::U8 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as u8;
|
||||
}
|
||||
}
|
||||
ParsedType::U16 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as u16;
|
||||
}
|
||||
}
|
||||
ParsedType::U32 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as u32;
|
||||
}
|
||||
}
|
||||
ParsedType::U64 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as u64;
|
||||
}
|
||||
}
|
||||
ParsedType::F32 => {
|
||||
quote::quote! {
|
||||
let #field = raw_record[#value_id] as f32;
|
||||
}
|
||||
}
|
||||
ParsedType::F64 => {
|
||||
quote::quote! {
|
||||
let #field = f64::from_bits(raw_record[#value_id as _]);
|
||||
}
|
||||
}
|
||||
ParsedType::Utf8String => {
|
||||
let ptr_id = value_id;
|
||||
let size_id = value_id + 1;
|
||||
value_id += 1;
|
||||
|
||||
quote::quote! {
|
||||
let #field = unsafe { String::from_raw_parts(raw_record[#ptr_id] as _, raw_record[#size_id] as _, raw_record[#size_id] as _) };
|
||||
}
|
||||
}
|
||||
ParsedType::ByteVector => {
|
||||
let ptr_id = value_id;
|
||||
let size_id = value_id + 1;
|
||||
value_id += 1;
|
||||
|
||||
quote::quote! {
|
||||
let #field = unsafe { Vec::from_raw_parts(raw_record[#ptr_id] as _, raw_record[#size_id] as _, raw_record[#size_id] as _) };
|
||||
}
|
||||
}
|
||||
ParsedType::Record(record_name) => {
|
||||
let ptr_id = value_id;
|
||||
let size_id = value_id + 1;
|
||||
value_id += 1;
|
||||
let deserializer_name =
|
||||
new_ident!(GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + record_name);
|
||||
|
||||
quote::quote! {
|
||||
let #field = #deserializer_name(raw_record[#ptr_id] as _, raw_record[#size_id] as _);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
field_values.push(field);
|
||||
deserializer.extend(field_d);
|
||||
value_id += 1;
|
||||
}
|
||||
|
||||
let type_constructor = match record.fields.first() {
|
||||
Some(ast_field) if ast_field.name.is_some() => {
|
||||
let field_names = record
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| new_ident!(field.name.clone().expect("all fields should have name")))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote::quote! {
|
||||
#ret_type {
|
||||
#(#field_names: #field_values),*
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(_) => {
|
||||
quote::quote! {
|
||||
#ret_type (
|
||||
#(#field_values),*
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => quote::quote! {},
|
||||
};
|
||||
|
||||
quote::quote! {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[doc(hidden)]
|
||||
#[allow(clippy::all)]
|
||||
unsafe fn #deserializer_fn_name(offset: i32, size: i32) -> #ret_type {
|
||||
let raw_record: Vec<u64> = Vec::from_raw_parts(offset as _, size as _, size as _);
|
||||
|
||||
#deserializer
|
||||
|
||||
#type_constructor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user