introduce trait FCERecordSerializer

This commit is contained in:
vms 2020-07-28 16:49:10 +03:00
parent 88afe8feaa
commit 141807945e
13 changed files with 55 additions and 78 deletions

View File

@ -45,6 +45,19 @@ pub use result::get_result_size;
pub use result::set_result_ptr; pub use result::set_result_ptr;
pub use result::set_result_size; pub use result::set_result_size;
/// This trait is used to convert structs to a form compatible with
/// record.lift_memory and record.lower_memory instructions.
/// Normally, this trait shouldn't be used directly.
pub trait FCEStructSerializable {
// Serialize the provided record to a Vec<u8>, returns pointer to it in a form compatible with
// record.lift_memory.
// The caller should manage the lifetime of returned pointer.
fn __fce_generated_serialize(self) -> *const u8;
// Deserialize record from a pointer (normally, come from record.lower_memory).
unsafe fn __fce_generated_deserialize(record_ptr: *const u8) -> Self;
}
#[allow(unused_variables)] #[allow(unused_variables)]
pub(crate) fn log<S: AsRef<str>>(msg: S) { pub(crate) fn log<S: AsRef<str>>(msg: S) {
// logs will be printed only if debug feature is enabled // logs will be printed only if debug feature is enabled

View File

@ -20,6 +20,7 @@
nonstandard_style, nonstandard_style,
unused_imports, unused_imports,
unused_mut, unused_mut,
unused_variables,
unused_unsafe, unused_unsafe,
unreachable_patterns unreachable_patterns
)] )]

View File

@ -16,7 +16,6 @@
use super::ParsedType; use super::ParsedType;
use crate::new_ident; use crate::new_ident;
use crate::token_stream_generator::GENERATED_RECORD_SERIALIZER_PREFIX;
use quote::quote; use quote::quote;
@ -97,11 +96,9 @@ fn generate_epilog(ty: &Option<ParsedType>) -> proc_macro2::TokenStream {
Some(ty) if !ty.is_complex_type() => quote! { Some(ty) if !ty.is_complex_type() => quote! {
return result as _; return result as _;
}, },
Some(ParsedType::Record(record_name)) => { Some(ParsedType::Record(_)) => {
let record_serializer =
crate::new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + record_name);
quote! { quote! {
let result_ptr = crate::#record_serializer(result); let result_ptr = result.__fce_generated_serialize();
fluence::internal::set_result_ptr(result_ptr as _); fluence::internal::set_result_ptr(result_ptr as _);
} }
} }

View File

@ -16,7 +16,6 @@
use super::ParsedType; use super::ParsedType;
use super::FnArgGlueCodeGenerator; use super::FnArgGlueCodeGenerator;
use crate::token_stream_generator::GENERATED_RECORD_DESERIALIZER_PREFIX;
use crate::new_ident; use crate::new_ident;
use crate::wasm_type::WasmType; use crate::wasm_type::WasmType;
@ -106,11 +105,9 @@ fn generate_type_prolog(
let #generated_arg_id = Vec::from_raw_parts(#ptr as _, #size as _, #size as _); let #generated_arg_id = Vec::from_raw_parts(#ptr as _, #size as _, #size as _);
}, },
ParsedType::Record(record_name) => { ParsedType::Record(record_name) => {
let record_deserializer = crate::new_ident!( let record_ident = new_ident!(record_name);
GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + record_name
);
quote! { quote! {
let #generated_arg_id = crate::#record_deserializer(#ptr); let #generated_arg_id = #record_ident::__fce_generated_deserialize(#ptr as _);
} }
} }
_ => panic!( _ => panic!(

View File

@ -31,13 +31,9 @@ impl ForeignModArgGlueCodeGenerator for ParsedType {
ParsedType::Utf8String | ParsedType::ByteVector => { ParsedType::Utf8String | ParsedType::ByteVector => {
quote! { #arg.as_ptr() as _, #arg.len() as _ } quote! { #arg.as_ptr() as _, #arg.len() as _ }
} }
ParsedType::Record(record_name) => { ParsedType::Record(_) => {
let record_serializer = crate::new_ident!(
crate::token_stream_generator::GENERATED_RECORD_SERIALIZER_PREFIX.to_string()
+ record_name
);
quote! { quote! {
crate::#record_serializer(#arg) #arg.__fce_generated_serialize() as _
} }
} }
_ => quote! { arg }, _ => quote! { arg },

View File

@ -59,12 +59,9 @@ impl ForeignModEpilogGlueCodeGenerator for Option<ParsedType> {
) )
}, },
Some(ParsedType::Record(record_name)) => { Some(ParsedType::Record(record_name)) => {
let record_deserializer = crate::new_ident!( let record_ident = new_ident!(record_name);
crate::token_stream_generator::GENERATED_RECORD_DESERIALIZER_PREFIX.to_string()
+ record_name
);
quote! { quote! {
crate::#record_deserializer(fluence::internal::get_result_ptr() as _) #record_ident::__fce_generated_deserialize(fluence::internal::get_result_ptr() as _)
} }
} }
_ => panic!( _ => panic!(

View File

@ -23,8 +23,6 @@ use crate::fce_ast_types::FCEAst;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
pub const GENERATED_WRAPPER_FUNC_PREFIX: &str = "__fce_generated_wrapper_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_SECTION_PREFIX: &str = "__fce_generated_section__";
pub const GENERATED_GLOBAL_PREFIX: &str = "__fce_generated_static_global_"; pub const GENERATED_GLOBAL_PREFIX: &str = "__fce_generated_static_global_";

View File

@ -68,6 +68,10 @@ impl quote::ToTokens for fce_ast_types::AstFunctionItem {
#[doc(hidden)] #[doc(hidden)]
#[allow(clippy::all)] #[allow(clippy::all)]
pub unsafe fn #func_name(#(#raw_arg_names: #raw_arg_types),*) #fn_return_type { pub unsafe fn #func_name(#(#raw_arg_names: #raw_arg_types),*) #fn_return_type {
// brings serialize/deserialize methods for records
#[allow(dead_code)]
use fluence::internal::FCEStructSerializable;
// arguments conversation from Wasm types to Rust types // arguments conversation from Wasm types to Rust types
#prolog #prolog

View File

@ -121,6 +121,10 @@ fn generate_wrapper_functions(extern_item: &fce_ast_types::AstExternModItem) ->
#[doc(hidden)] #[doc(hidden)]
#[allow(clippy::all)] #[allow(clippy::all)]
#visibility fn #func_name(#(#arg_names: #arg_types), *) #return_type { #visibility fn #func_name(#(#arg_names: #arg_types), *) #return_type {
// brings serialize/deserialize methods for records
#[allow(dead_code)]
use fluence::internal::FCEStructSerializable;
unsafe { unsafe {
// calling the original function with converted args // calling the original function with converted args
#return_expression #import_func_name(#(#raw_args), *); #return_expression #import_func_name(#(#raw_args), *);

View File

@ -20,9 +20,6 @@ mod record_deserializer;
use record_serializer::*; use record_serializer::*;
use record_deserializer::*; use record_deserializer::*;
use super::GENERATED_RECORD_SERIALIZER_PREFIX;
use super::GENERATED_RECORD_DESERIALIZER_PREFIX;
use crate::new_ident; use crate::new_ident;
use crate::fce_ast_types; use crate::fce_ast_types;
@ -38,6 +35,7 @@ impl quote::ToTokens for fce_ast_types::AstRecordItem {
global_static_name, global_static_name,
section_name section_name
); );
let record_name = new_ident!(self.name);
let serializer_fn = generate_serializer_fn(self); let serializer_fn = generate_serializer_fn(self);
let deserializer_fn = generate_deserializer_fn(self); let deserializer_fn = generate_deserializer_fn(self);
@ -48,12 +46,11 @@ impl quote::ToTokens for fce_ast_types::AstRecordItem {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
#[doc(hidden)] #[doc(hidden)]
#[allow(clippy::all)] #[allow(clippy::all)]
#serializer_fn impl fluence::internal::FCEStructSerializable for #record_name {
#serializer_fn
#[cfg(target_arch = "wasm32")] #deserializer_fn
#[doc(hidden)] }
#[allow(clippy::all)]
#deserializer_fn
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
#[doc(hidden)] #[doc(hidden)]
@ -67,16 +64,10 @@ impl quote::ToTokens for fce_ast_types::AstRecordItem {
} }
fn generate_serializer_fn(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream { fn generate_serializer_fn(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream {
let serializer_fn_name = let serializer = record.generate_serializer();
new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + &record.name);
let RecordSerializerDescriptor {
serializer,
record_type,
} = record.generate_serializer(&record.name);
quote::quote! { quote::quote! {
pub(in crate) fn #serializer_fn_name(record: #record_type) -> i32 { fn __fce_generated_serialize(self) -> *const u8 {
let mut raw_record = Vec::new(); let mut raw_record = Vec::new();
#serializer #serializer
@ -90,21 +81,17 @@ fn generate_serializer_fn(record: &fce_ast_types::AstRecordItem) -> proc_macro2:
} }
fn generate_deserializer_fn(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream { fn generate_deserializer_fn(record: &fce_ast_types::AstRecordItem) -> proc_macro2::TokenStream {
let deserializer_fn_name =
new_ident!(GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + &record.name);
let RecordDeserializerDescriptor { let RecordDeserializerDescriptor {
deserializer, deserializer,
type_constructor, type_constructor,
return_type, } = record.generate_deserializer();
} = record.generate_deserializer(&record.name);
let record_size = let record_size =
crate::utils::get_record_size(record.fields.iter().map(|ast_field| &ast_field.ty)); crate::utils::get_record_size(record.fields.iter().map(|ast_field| &ast_field.ty));
quote::quote! { quote::quote! {
pub(in crate) unsafe fn #deserializer_fn_name(offset: i32) -> #return_type { unsafe fn __fce_generated_deserialize(record_ptr: *const u8) -> Self {
let raw_record: Vec<u64> = Vec::from_raw_parts(offset as _, #record_size, #record_size); let raw_record: Vec<u64> = Vec::from_raw_parts(record_ptr as _, #record_size, #record_size);
#deserializer #deserializer

View File

@ -17,25 +17,21 @@
use crate::new_ident; use crate::new_ident;
use crate::parsed_type::ParsedType; use crate::parsed_type::ParsedType;
use crate::fce_ast_types; use crate::fce_ast_types;
use crate::token_stream_generator::GENERATED_RECORD_DESERIALIZER_PREFIX;
use quote::quote; use quote::quote;
pub(super) struct RecordDeserializerDescriptor { pub(super) struct RecordDeserializerDescriptor {
pub(super) deserializer: proc_macro2::TokenStream, pub(super) deserializer: proc_macro2::TokenStream,
pub(super) type_constructor: proc_macro2::TokenStream, pub(super) type_constructor: proc_macro2::TokenStream,
pub(super) return_type: syn::Ident,
} }
/// This trait could be used to generate various parts of a record serializer func. /// This trait could be used to generate various parts of a record serializer func.
pub(super) trait RecordDeserializerGlueCodeGenerator { pub(super) trait RecordDeserializerGlueCodeGenerator {
fn generate_deserializer(&self, record_name: &str) -> RecordDeserializerDescriptor; fn generate_deserializer(&self) -> RecordDeserializerDescriptor;
} }
impl RecordDeserializerGlueCodeGenerator for fce_ast_types::AstRecordItem { impl RecordDeserializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
fn generate_deserializer(&self, record_name: &str) -> RecordDeserializerDescriptor { fn generate_deserializer(&self) -> RecordDeserializerDescriptor {
let return_type = new_ident!(record_name);
let mut field_values = Vec::with_capacity(self.fields.len()); let mut field_values = Vec::with_capacity(self.fields.len());
let mut deserializer = proc_macro2::TokenStream::new(); let mut deserializer = proc_macro2::TokenStream::new();
let mut value_id: usize = 0; let mut value_id: usize = 0;
@ -118,11 +114,9 @@ impl RecordDeserializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
} }
ParsedType::Record(record_name) => { ParsedType::Record(record_name) => {
let ptr_id = value_id; let ptr_id = value_id;
let record_deserializer = let record_ident = new_ident!(record_name);
new_ident!(GENERATED_RECORD_DESERIALIZER_PREFIX.to_string() + record_name);
quote! { quote! {
let #field = crate::#record_deserializer(raw_record[#ptr_id] as _); let #field = #record_ident::__fce_generated_deserialize(raw_record[#ptr_id] as _);
} }
} }
}; };
@ -143,14 +137,14 @@ impl RecordDeserializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
quote! { quote! {
#return_type { Self {
#(#field_names: #field_values),* #(#field_names: #field_values),*
} }
} }
} }
Some(_) => { Some(_) => {
quote! { quote! {
#return_type ( Self (
#(#field_values),* #(#field_values),*
) )
} }
@ -161,7 +155,6 @@ impl RecordDeserializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
RecordDeserializerDescriptor { RecordDeserializerDescriptor {
deserializer, deserializer,
type_constructor, type_constructor,
return_type,
} }
} }
} }

View File

@ -17,22 +17,16 @@
use crate::new_ident; use crate::new_ident;
use crate::parsed_type::ParsedType; use crate::parsed_type::ParsedType;
use crate::fce_ast_types; use crate::fce_ast_types;
use crate::token_stream_generator::GENERATED_RECORD_SERIALIZER_PREFIX;
use quote::quote; use quote::quote;
pub(super) struct RecordSerializerDescriptor {
pub(super) serializer: proc_macro2::TokenStream,
pub(super) record_type: syn::Ident,
}
/// This trait could be used to generate various parts of a record serializer func. /// This trait could be used to generate various parts of a record serializer func.
pub(super) trait RecordSerializerGlueCodeGenerator { pub(super) trait RecordSerializerGlueCodeGenerator {
fn generate_serializer(&self, record_name: &str) -> RecordSerializerDescriptor; fn generate_serializer(&self) -> proc_macro2::TokenStream;
} }
impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem { impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
fn generate_serializer(&self, record_name: &str) -> RecordSerializerDescriptor { fn generate_serializer(&self) -> proc_macro2::TokenStream {
let mut serializer = proc_macro2::TokenStream::new(); let mut serializer = proc_macro2::TokenStream::new();
for (id, field) in self.fields.iter().enumerate() { for (id, field) in self.fields.iter().enumerate() {
let field_ident = field_ident(field, id); let field_ident = field_ident(field, id);
@ -50,11 +44,9 @@ impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
std::mem::forget(#field_ident); std::mem::forget(#field_ident);
} }
} }
ParsedType::Record(record_name) => { ParsedType::Record(_) => {
let record_serializer =
new_ident!(GENERATED_RECORD_SERIALIZER_PREFIX.to_string() + &record_name);
quote! { quote! {
raw_record.push(crate::#record_serializer(#field_ident) as _); raw_record.push(#field_ident.__fce_generated_serialize() as _);
} }
} }
_ => quote! { _ => quote! {
@ -64,12 +56,8 @@ impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
serializer.extend(field_serialization); serializer.extend(field_serialization);
} }
let record_type = new_ident!(record_name);
RecordSerializerDescriptor { serializer
serializer,
record_type,
}
} }
} }
@ -77,11 +65,11 @@ fn field_ident(field: &fce_ast_types::AstRecordField, id: usize) -> proc_macro2:
match &field.name { match &field.name {
Some(name) => { Some(name) => {
let name = new_ident!(name); let name = new_ident!(name);
quote! { record.#name } quote! { self.#name }
} }
None => { None => {
let id = new_ident!(format!("{}", id)); let id = new_ident!(format!("{}", id));
quote! { record.#id } quote! { self.#id }
} }
} }
} }

View File

@ -45,4 +45,6 @@ pub mod internal {
pub use fluence_sdk_main::get_result_size; pub use fluence_sdk_main::get_result_size;
pub use fluence_sdk_main::set_result_ptr; pub use fluence_sdk_main::set_result_ptr;
pub use fluence_sdk_main::set_result_size; pub use fluence_sdk_main::set_result_size;
pub use fluence_sdk_main::FCEStructSerializable;
} }